c - 读取文件并通过管道将其发送到父进程的程序

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

最佳答案

经过相当多的更改后,您的程序可以按预期运行。让我们列出需要进行哪些更改以及原因-

I) 在子级和父级中,使用完毕后立即关闭相应的管道。来自 man page 读取(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 返回多次时,这会发生爆炸,在此过程中每次都会覆盖缓冲区

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

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

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

IV) child 和家长完成工作后,请安全退出。类似的东西

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

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

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

关于c - 读取文件并通过管道将其发送到父进程的程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10139470/

相关文章:

java - 异常在线程 "IDL"java.lang.UnsatisfiedLinkError : no idl_ips in java. library.path

c - 将结构传递给 C 中的函数

c - 我怎样才能使这个结构在 C 中工作?

c++ - 动态链接到 Boost 的库而不是仅 header

php - 为 php 开发人员推荐的 linux 教程/书籍?

c - 管道时,为什么在使用 dup2() 之前必须关闭() 管道的另一端?

php - 从 php 到 ffmpeg 的图像管道

bash - 如何在启用了 “head”的脚本中使用 “pipefail”?

c++ - 为什么 msgrcv() 将垃圾字符输入缓冲区?

c - 从不兼容的指针类型传递 arg2 'listFind'