2

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

这是我的代码,它会沿文件文件打印一些垃圾(并且当我运行它时它会禁用终端模拟器中的滚动)。

#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);
}
4

3 回答 3

2

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

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

于 2012-04-13T11:05:57.527 回答
2

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

I) 在孩子和父母中,一旦你完成它们,就关闭各自的管道。从手册read(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:我已经更改了文件读取逻辑,因此您的编译器错误现在消失了,请遵循nm给出的建议。

于 2012-04-13T12:24:38.940 回答
0

此代码无法编译:

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

你不能在else那里有一个子句。

于 2012-04-13T11:02:46.643 回答