c - 多个子进程将使用 popen 执行的 unix 命令的结果写入父进程

标签 c unix pipe fork popen

我必须编写一个 C 代码:

  • 接受 'n' 个命令行参数(unix 命令)
  • 对于每个参数,主程序启动两个子进程
  • 每个子进程将随机延迟并使用 popen 执行 unix 命令 (args[i]),然后将答案发送给父进程 父进程将仅打印收到的前 n/2 个响应
  • 父进程与子进程之间的通信只能使用管道 channel

我编写了如下源代码:

    #include <stdio.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <wait.h>
    #include <time.h>
    #include <string.h>
    #include <errno.h>

    #define DIM 100

    int main(int argc, char *args)
    {
       int t, nrR=argc-1,f,p[2],prID,d;
       FILE *fd1, *fd2;

       //PIPE channel creation
       if(pipe(p)<0)
       {
          perror("PIPE channel creation error!");
          exit(1);
       }
       for(i=1;i<argc;i++)
       {
          d=strlen(args[i]);

          if((f=fork())==0)
          {  //FIRST CHILD PROCESS

             char *buffer = malloc(DIM*sizeof(char));
             //The child process will only write to the parent process
             close(p[0]);
             //Delay the process execution
             srand(time(NULL));
             int s=rand()%2;
             sleep(s);
             fd1 = popen(args[i],"r");

             //Writing the PID to the parent process
             prID=getpid();
             if(write(p[1],&prID,sizeof(int))!=sizeof(int))
             {
                perror("PIPE writing error!");
                exit(3);
             }

             //Writing the command string length
             if(write(p[1],&d,sizeof(int))!=sizeof(int))
             {
                perror("PIPE writing error!");
                exit(3);
             }

             //Writing the command string
             if(write(p[1],args[i],sizeof(args[i]))!=sizeof(args[i]))
             {
                perror("PIPE writing error!");
                exit(3);
             }

             //Writing the command output result string
             while(fread(buffer,DIM,1,fd1)>0)
             {
                if(write(p[1],buffer,sizeof(buffer))!=sizeof(buffer))
                {
                    perror("PIPE writing error!");
                    exit(3);
                }
             }
             free(buffer);  
             pclose(fd1);
             exit(i+1);
          }
          else if((f=fork())==0)
          {  //SECOND CHILD PROCESS
             char *buffer = malloc(DIM*sizeof(char));
             //The child process will only write to the parent process
             close(p[0]);
             //Delay the process execution
             srand(time(NULL));
             int s=rand()%2;
             sleep(s);
             fd2 = popen(args[i],"r");

             //Writing the PID to the parent process
             prID=getpid();
             if(write(p[1],&prID,sizeof(int))!=sizeof(int))
             {
                perror("PIPE writing error!");
                exit(3);
             }

             //Writing the command string length
             if(write(p[1],&d,sizeof(int))!=sizeof(int))
             {
                perror("PIPE writing error!");
                exit(3);
             }

             //Writing the command string
             if(write(p[1],args[i],sizeof(args[i]))!=sizeof(args[i]))
             {
                perror("PIPE writing error!");
                exit(3);
             }

             //Writing the command output result string
             while(fread(buffer,DIM,1,fd2)>0)
             {
                if(write(p[1],buffer,sizeof(buffer))!=sizeof(buffer))
                {
                    perror("PIPE writing error!");
                    exit(3);
                }
             }
             free(buffer);  
             pclose(fd2);
             exit(i+2);
          } 
       }
       if(f>0)
       {
          //Parent process behavior
          close(p[1]); //The parent process will not write to the child processes
          for(i=0;i<nrR;i++)
          {
             //we will read and print only the first 'n' responses received through the pipe channel from the child processes
             waitpid(-1,NULL,0);
             char *cmd,*buffer;

             //Read the pid of the child process
             if(read(p[0],&prID,sizeof(int))!=sizeof(int))
             {
                perror("PIPE reading error!")
                exit(2);
             }
             //Read the command string length
             if(read(p[0],&d,sizeof(int))!=sizeof(int))
             {
                perror("PIPE reading error!")
                exit(2);
             }
             //Read the command
             cmd = malloc(d*sizeof(char));
             if(read(p[0],cmd,sizeof(cmd))!=sizeof(cmd))
             {
                perror("PIPE reading error!")
                exit(2);
             }
             printf("\nProcess %d -> %s:\n",prID,cmd);
             //Read and print the unix command result
             buffer = malloc(DIM*sizeof(char));
             while(read(p[0],buffer,sizeof(buffer))>0)
             {
                printf("%s",buffer);
             }
             free(buffer);
             free(cmd);

             //Wait for other n/2 child processes to terminate
             while(waitpid(-1,NULL,0)>0)
             {
                if(errno == ECHILD)
                   break;
             }
          }
       }
       return 0;
    }

我的代码编译并运行;我试过“ls”作为参数。该程序没有显示预期的输出。我介绍了一些支票打印,并检测到以下问题:

  • 在子进程中,我无法读取 fd1 和 fd2 的整个“ls”输出
  • 父进程没有收到任何东西/没有正确收到子进程通过管道发送的“ls”输出字符串(它虽然正确收到了子进程 ID 和命令名称)。

多个子进程尝试(可能同时)写入同一个 PIPE channel 是否会导致问题?还是有其他一些我没有想到的问题?

非常感谢。

最佳答案

每个 child 都需要它自己的管道返回父级,所以 p 应该是一个二维数组,p[child][file id]。 您绝不会尝试收集命令数据,也不会访问与命令的标准输出相关的管道。您打算如何将命令输出发送回父级。您需要告诉 parent 有多少字节的文本即将到来,然后将其全部写入可能是最好的解决方案。它允许您 malloc 准备好将其存储为字符串的缓冲区,并且它也可以被 block 读取而不是一次读取一个字节,直到 '\0'

关于c - 多个子进程将使用 popen 执行的 unix 命令的结果写入父进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29926927/

相关文章:

c - 写入标准输入以进行自制管道

linux - 如何在 Linux 中使用 lynx/w3m 提取多个 URL 的文本

c - 在谈论数组时, "dimension"是什么意思?”

c - 带有指向 char 数组的指针的链表

结合 fork、fifo 和 execlp?

bash - 如何在 unix 系统中关闭来自另一个进程的文件描述符

将 MIPs 指令转换为 C 并减少执行

c - time.h 中是否有设置内部缓冲区的函数

linux - 如何使用shell脚本更改csv文件中单元格的值

c - 我应该如何使用 FIFO 等待子进程的输入