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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10139470/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:46:08  来源:igfitidea点击:

Program that read file and send it to parent process with pipe

clinuxpipe

提问by jcubic

I need to write a program that create pipe send filename from command line to child process. In child read that file and send it back using pipe. Parent process should print the file. if error occur in child process error must be send to parent process.

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

here is my code, it print some junk along file file (and also it disable scrolling in terminal emulator when I run it).

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

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

采纳答案by Pavan Manjunath

Your program works as intended after quite a few changes. Lets list out what all changes are required and why-

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

I)Both in the child and parent, close the respective pipes as soon as you are done with them. From man pageof read(3),

I)在孩子和父母中,完成后立即关闭各自的管道。从手册页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.

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

So do something like this in your code everywhere where the job pipes is over,

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

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

You hadn't closed the write end of of the pipe in the child and your parent was blocking in the read

您没有关闭孩子管道的写端,而您的父母正在阻止 read

II)You are using something like while(fgets(...))in a loop to read data from file. This will bomb when there are newlines in the file and fgetsreturns multiple times, overwriting the buffereverytime during the process

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

I always use simple fgetcand feofcombination to read from file. So, change your file reading mechanism to something like

我总是使用简单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)While writing the file data from the child, you should use strlen(as we have already made sure buffer is null terminated, see above ) and not sizeofas the buffer may not be full at alland you will end up writing junk. So, change

III)在从子进程写入文件数据时,您应该使用strlen(因为我们已经确保缓冲区为空终止,请参见上文),而不是sizeof因为缓冲区可能根本没有满,您最终会写入垃圾。所以,改变

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

to

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

IV)Follow a safe exitfrom the child and parent after their job is done. Something like

IV)exit在孩子和家长完成工作后,跟着他们的保险箱。就像是

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

and

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

PS: I've changed the file reading logic, so your compiler error is gone now and do follow the advice given by n.m.

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

回答by Jonathan Leffler

This code does not compile:

此代码无法编译:

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

You can't have an elseclause there.

你不能在else那里有一个条款。

回答by n. 'pronouns' m.

You cannot write sizeof(buf)meaningful bytes if fgetsreturned less than that. The rest will be filled with junk.

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

Moreover, mixing string-oriented fgetswith binary read/writeis a bad style. Use reador freadto read the file. They return number of bytes read, use this number as an argument to write.

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