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

时间:2012-04-13 10:52:35

标签: c 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);
}

3 个答案:

答案 0 :(得分:2)

如果sizeof(buf)返回的内容少于此值,则无法写入fgets有意义的字节。其余的将充满垃圾。

此外,将面向字符串的fgets与二进制read/write混合是一种糟糕的风格。使用readfread来读取文件。它们返回读取的字节数,将此数字用作write的参数。

答案 1 :(得分:2)

经过多次更改,您的程序按预期工作。让我们列出所需的所有更改以及原因 -

I)在孩子和父母身上,一旦完成,就关闭相应的管道。来自read(3)的{​​{3}},

  

如果某个进程打开了管道并且O_NONBLOCK已清除,   read()将阻塞调用线程,直到写入一些数据或   管道由管道打开的所有进程关闭   写入。

所以在你的代码中,在作业管道结束的地方做这样的事情,

  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]);

您尚未关闭子级中管道的写入结束,而您的父级已在read

中阻止

II)您在循环中使用类似while(fgets(...))的内容来从文件中读取数据。 当文件中有换行符并且fgets多次返回时,这会爆炸,在此过程中每次都覆盖buffer

我总是使用简单的fgetcfeof组合来读取文件。因此,将文件读取机制更改为

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 (因为我们已经确保缓冲区为空终止,见上文)而不是sizeof,因为缓冲区可能根本不是满的,你最终会写垃圾。所以,改变

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

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

IV)在完成工作后,请关注孩子和家长的安全exit。像

这样的东西
close(pipefd[1]);
_exit(EXIT_SUCCESS);   // in child

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

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

答案 2 :(得分:0)

此代码无法编译:

  while (fgets(buff, sizeof(buff), file) != NULL) {
        write(pipefd[1], "Error reading file", 18);
     } else {
        write(pipefd[1], buff, sizeof(buff));
     }

你不能在那里有else条款。