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

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

#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给出的建议.

标签: linux, pipe

相关文章推荐

添加新评论,含*的栏目为必填