ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

程序读取文件并使用管道将其发送到父进程

2019-10-09 09:51:54  阅读:162  来源: 互联网

标签:c-3 linux pipe


我需要编写一个程序,该程序创建从命令行到子进程的管道发送文件名.在子进程中,读取该文件并使用管道将其发送回去.父进程应打印文件.如果子进程中发生错误,则必须将错误发送给父进程.

这是我的代码,它在文件中打印出一些垃圾(并且在运行它时,它也无法在终端仿真器中滚动).

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void main(int argc, char *argv[]) {
   int pipefd[2];
   char buff[100];
   int childpid;
   int size;
   FILE *file;

   if (argc != 2) {
      printf("usage:\n%s <filename>\n", argv[0]);
      exit(1);
   }
   if (pipe(pipefd) < 0) {
       perror("can't open pipe\n");
   }
   if ((childpid = fork()) == 0) {
      sleep(1);
      size = read(pipefd[0], buff, sizeof(buff));
      file = fopen(buff, "r");
      if (file == NULL) {
         write(pipefd[1], "Can't open file", 15);
         exit(1);
      }
      while (!feof(file)) {
         if (fgets(buff, sizeof(buff), file) == NULL) {
            write(pipefd[1], "Error reading file", 18);
         } else {
            write(pipefd[1], buff, sizeof(buff));
         }
      }
   } else if (childpid > 0) {
      size = strlen(argv[1]);
      if (write(pipefd[1], argv[1], size) != size) {
         perror("Error writing to pipe\n");
      }
      wait(NULL);
      while ((size = read(pipefd[0], buff, sizeof(buff))) > 0) {
         write(1, buff, size);
      }
   }
   exit(0);
}

解决方法:

经过相当多的更改,您的程序可以按预期工作.让我们列出所有需要进行的更改以及为什么-

I)完成对它们的处理后,立即在孩子和父母中关闭各自的管道.从man page的read(3)中,

If some process has the pipe open for writing and O_NONBLOCK is clear,
read() shall block the calling thread until some data is written or
the pipe is closed by all processes that had the pipe open for
writing.

因此,在作业管道结束的所有地方,在您的代码中执行类似的操作,

  size = read(pipefd[0], buff, sizeof(buff));
  close(pipefd[0]);

  write(pipefd[1], buff, strlen(buff));
  close(pipefd[1]);

  if (write(pipefd[1], argv[1], size) != size) {
     perror("Error writing to pipe\n");
  }
  close(pipefd[1]);

  while ((size = read(pipefd[0], buff, sizeof(buff))) > 0) 
  {
     write(1, buff, size);
  }
  close(pipefd[0]);

您没有在孩子中关闭管道的写入端,而您的父母在读取中阻塞了

II)您正在循环中使用诸如while(fgets(…))之类的内容从文件中读取数据.当文件中有换行符时,它将炸弹,并且fgets返回多次,在此过程中每次覆盖缓冲区

我总是使用简单的fgetc和feof组合来读取文件.因此,将文件读取机制更改为类似

unsigned count=0;
while (!feof(file) && count < sizeof(buff))
    buff[count++]=fgetc(file);
if (feof(file)) 
    buff[--count]=0;
else
    buff[sizeof(buff)-1]=0;

III)从子级写入文件数据时,应使用strlen(因为我们已经确保缓冲区以null结尾,请参见上文),而不要使用sizeof,因为缓冲区可能根本不满,并且最终将导致写入垃圾.所以,改变

  write(pipefd[1], buff, sizeof(buff));

  write(pipefd[1], buff, strlen(buff));

IV)完成工作后,请从孩子和父母那里安全退出.就像是

close(pipefd[1]);
_exit(EXIT_SUCCESS);   // in child

close(pipefd[0]);
exit(EXIT_SUCCESS); // in parent

PS:我已经更改了文件读取逻辑,因此您的编译器错误现在消失了,并且请遵循n.m给出的建议.

标签:c-3,linux,pipe
来源: https://codeday.me/bug/20191009/1878029.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有