简体   繁体   English

将单个进程写入 C 中的两个管道

[英]Having a single process write to two pipes in C

I'm trying to implement a program that launches a process (call this app1) and pipes the stdout to two other apps (app2, app3 respectively).我正在尝试实现一个启动进程(调用此 app1)并将标准输出通过管道传输到其他两个应用程序(分别为 app2、app3)的程序。 I have a functioning implementation where I fork() app1 twice and pipe the stdout for each, but I feel there's a cleaner solution.我有一个正常运行的实现,我 fork() app1 两次,每个 pipe 的标准输出,但我觉得有一个更干净的解决方案。

What happens with my implementation is that app3 launches but doesn't show the stdout in the shell. Not looking for an exact answer to my problem, but a nudge in the right direction.我的实现发生的情况是 app3 启动但没有在 shell 中显示标准输出。不是在寻找我的问题的确切答案,而是在正确的方向上推动。 I believe the issue is how I'm handling the file descriptors, but I'm still quite new to these functions so I'm not sure where I went wrong.我相信问题在于我如何处理文件描述符,但我对这些功能还很陌生,所以我不确定哪里出错了。

Here is what I have:这是我所拥有的:

int pipepipe(char **app1, char **app1, char**app3){
   int fd[4]; 
   pipe(fd);
   pipe(fd+2);
   pid_t pid1 = fork();
   if(pid1 < 0){
      return 2;
   }
   if (pid1 == 0){ 
      dup2(fd[1], 1);
      dup2(fd[3], 1);
      for(int i = 0; i <4; i++){
         close(fd[i]);
      }
      execvp(app1[0], app1); 
   }

   int pid2 = fork();
   if(pid2 <0){
      return 2; 
   }
   if(pid2 == 0){ 
      dup2(fd[0], 0); 
      for(int i = 0; i <4; i++){
         close(fd[i]);
      }
      execvp(app2[0], app2);
   } 

   int pid3 = fork();
   if(pid3 < 0){
      return 2;
   }
   if(pid3 == 0){
      dup2(fd[2], 0);
      for(int i = 0; i < 4; i++){
         close(fd[i]);
      }
      execvp(app3[0], app3);
   }
   
   waitpid(pid1, NULL, 0);
   waitpid(pid2, NULL, 0);
   waitpid(pid3, NULL, 0);

   for(int i = 0; i <4; i++){
      close(fd[i]);
      }
   return 0;
} 

The consecutive calls:连续调用:

dup2(fd[1], 1);
dup2(fd[3], 1);

in the app1 child code are wrong. app1中的子代码是错误的。 Individually, they're fine, but the second call closes the fd[1] that was duplicated to STDOUT_FILENO (aka 1 ).单独地,它们很好,但第二次调用关闭了复制到STDOUT_FILENO (又名1 )的fd[1] You have to use two separate file descriptors to write to the two pipes.您必须使用两个单独的文件描述符来写入两个管道。 So, rather than app1 writing to its standard output, you'll probably want to think about passing (string) arguments which tell it which file descriptors to write on.因此,而不是app1写入其标准 output,您可能需要考虑传递(字符串)arguments,它告诉它要写入哪些文件描述符。 All command arguments are strings, so maybe:所有命令 arguments 都是字符串,所以可能:

char out1[6];
char out2[6];
sprintf(out1, "-o%d", fd[1]);
sprintf(out2, "-o%d", fd[3]);

and then add out1 and out2 to the arguments in the app1 array.然后将out1out2添加到app1数组中的 arguments。 You'd not close either fd[1] or fd[3] ;您不会关闭fd[1]fd[3] you would still close fd[0] and fd[2] .你仍然会关闭fd[0]fd[2]

If you need to differentiate between the two apps (if app1 writes different data to app2 and app3 ), then you use different option letters (maybe -o and -O ?) to identify which is which.如果您需要区分这两个应用程序(如果app1将不同的数据写入app2app3 ),那么您可以使用不同的选项字母(可能是-o-O ?)来识别哪个是哪个。

Obviously, you need appropriate argument parsing code in app1 so it knows what to do.显然,您需要在app1中使用适当的参数解析代码,以便它知道该做什么。

The alternative is designate that file descriptor 3 will be the output to app2 and file descriptor 4 will be the output to app3 (leaving the standard I/O descriptors unchanged):另一种方法是指定文件描述符 3 为app2的 output,文件描述符 4 为app3的 output(保持标准 I/O 描述符不变):

dup2(fd[1], 3);
dup2(fd[2], 4);

You just have to be a bit careful that you don't close either 3 or 4 in the loop over the 4 file descriptors.您只需要小心一点,不要在 4 个文件描述符的循环中关闭 3 或 4。 The chances are that you have the following numbers:您可能有以下数字:

fd[0] = 3
fd[1] = 4
fd[2] = 5
fd[3] = 6

in which case, the two dup calls would be fine, but the close loop would need to avoid closing fd[0] and fd[1] (because those values are 3 and 4).在这种情况下,两个 dup 调用会很好,但闭环需要避免关闭fd[0]fd[1] (因为这些值为 3 和 4)。

On the whole, I prefer the explicit options, but YMMV.总的来说,我更喜欢显式选项,但 YMMV。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM