流程之间的管道链

时间:2012-01-10 23:21:23

标签: c pipe dup2

我希望有一个父母和2个孩子。

父文件从文件“a.txt”读取并将管道发送给第一个孩子;第一个孩子读取字符并向第二个孩子发送较低字母的字符。

第二个孩子在“b.txt”中打印每个不同的字符和出现次数(每行),然后通过管道向父母发送不同字符的数量。父节点打印第二个孩子的结果。

我已经完成了从父母到1个孩子的管道,并且测试我已经将管道放回到父管道。 我无法弄明白的是如何让管道进入第二个孩子。我一直在寻找有关dup2的信息,但我不知道如何使其发挥作用。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>

void main()
{

    int pfd1[2], pfd2[2], pid1, pid2, pfin, status, fd;
    char *c = (char *)malloc(sizeof(char));

    if (pipe(pfd1) < 0) {
        printf("Eroare la crearea pipe-ului\n");
        exit(1);
    }
    if (pipe(pfd2) < 0) {
        printf("Eroare la crearea pipe-ului\n");
        exit(1);
    }
    if ((pid1 = fork()) < 0) {
        printf("Eroare la fork\n");
        exit(1);
    }

    if (pid1 == 0) {    /*child */
        close(pfd1[1]);
        while (read(pfd1[0], c, 1) > 0) {
            //printf("%s",c);
            if (islower(*c)) {
                close(pfd2[0]);
                //inchid capul de citire; scriu in pipe
                write(pfd2[1], c, 1);
                ////dup??????
            }
        }
        printf("\n");
        write(pfd[1], buff, len);

        close(pfd1[0]);
        close(pfd2[1]);
        exit(0);
    }

    if ((pid2 = fork()) < 0) {
        printf("Eroare la fork\n");
        exit(1);
    }

    if (pid2 == 0) {
        printf("second child");
        exit(0);
    }

    /* parent */
    close(pfd1[0]);
    close(pfd2[1]);
    fd = open("date.txt", O_RDONLY);
    while (read(fd, c, 1) > 0) {
        write(pfd1[1], c, 1);
    }
    close(pfd1[1]);     /* la sfarsit inchide si capatul utilizat */
    close(pfin);

    while (read(pfd2[0], c, 1) > 0)
        printf("%s", c);
    close(pfd2[0]);
    printf("%d", wait(&status));
    printf("%d", wait(&status));

}

3 个答案:

答案 0 :(得分:2)

我对您的代码有一些具体的评论:

char *c = (char *)malloc(sizeof(char));

虽然这没有任何问题,但也不需要从堆中分配此char。更惯用的方法是在此使用char c;,然后将&c传递给read(2)write(2)系统调用。 (更惯用的是使用C标准IO工具; freopen(3)getchar(3)putchar(3) - 但在此代码完全按照您的要求运行之前不要进行转换它,因为它是你试图解决的问题的另一个复杂因素。)

if ((pid1 = fork()) < 0) {
    printf("Eroare la fork\n");
    exit(1);
}

通过使用您自己的错误消息,您错过了重要的错误信息。您应该使用perror(3)来打印错误消息。这将为您和您的用户提供他们可以搜索的错误的实际原因。如果您的用户遇到fork(2) setrlimit(2)最大进程限制(系统范围的进程限制,超出内核内存),则NPROC可能会失败。

if ((pid1 = fork()) < 0) {
   perror("Eroare la fork");
   exit(1);
}

您还应该检查open(2)来电的返回值。 (你假设也检查来自write(2)close(2)的返回值是否有错误,但处理这些错误更难。只需打印错误并退出就是一个好的开始对于大多数程序。)

    while (read(pfd1[0], c, 1) > 0) {
        //printf("%s",c);
        if (islower(*c)) {
            close(pfd2[0]);

这是close(2)调用的错误位置 - 您不应该为每个输入字符反复关闭此文件描述符。如果您检查close(2)返回值,您会注意到errno设置为EBADF,因为文件描述符在第二次和后续调用中不再有效。

现在,针对您来到这里的问题:fork()pipe()dup2()调用的序列将挂接管道中的所有进程并将数据发送回父进程。由于pipe(2)会创建单向pipe(7),因此您需要为父级和子级之间的两个方向调用pipe(2) 四次。如果将管道端点存储在具有对您有意义的名称的数组中,则可以更容易地跟踪它们。也许创建名为to_的数组用于写入和from_用于阅读:

int to_child[2];
int from_parent[2];
int to_parent[2];
int from_child[2];

for (int i=0; i<2; i++) {
    int p[2];

    if (pipe(p) == -1) {
    perror("pipe");
    exit(1);
    }

    /* from parent to child */

    to_child[i] = p[1];
    from_parent[i] = p[0];

    if (pipe(p) == -1) {
    perror("pipe");
    exit(1);
    }

    /* from child to parent */

    to_parent[i] = p[1];
    from_child[i] = p[0];
}

请注意,除非您想执行其他程序来处理“过滤器”,否则您实际上 不需要使用dup2(2)来重新排列文件描述符“任务。只需read(2)使用from_parent[...]from_child[...]描述符,write(2)使用to_child[...]to_parent[...]描述符。

使用socketpair(2) AF_UNIX创建双向套接字可能会让整个过程变得更容易,然后可以像以下相同的方式读取和写入任何其他BSD风格的插座。有关概述,请参阅socket(7)unix(7)

答案 1 :(得分:0)

您不需要dup()。只需在父进程中打开管道,然后在每个进程中close()打开您不需要的端点,只需使用您需要的端点。

请注意,这意味着父级将关闭管道的两个端点以进行子级通信。该管道的每个端点将由其中一个子节点使用。每个孩子也应该关闭它不使用的端点。

答案 2 :(得分:0)

感谢您的回答。 这是整个问题的代码。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>

void main()
{

 int pfd1[2],pfd2[2],pfd3[2],pid1,pid2,status,fd,fo;
 char letter[32][2];
 int letternumber=0,i,sw=0;
 char* c = (char*)malloc(sizeof(char));
 //pipe creation
 if(pipe(pfd1)<0){ 
    perror("Eroare la crearea pipe-ului"); 
    exit(1); 
 } 

 if(pipe(pfd2)<0){ 
    perror("Eroare la crearea pipe-ului\n"); 
    exit(1); 
 }

 if(pipe(pfd3)<0){ 
    perror("Eroare la crearea pipe-ului\n"); 
    exit(1); 
 }  
 //make first child
 if((pid1=fork())<0){ 
    perror("Eroare la fork\n"); 
    exit(1); 
 } 
 if(pid1==0) //child process
 { 
 if(close(pfd1[1])<0) {perror("Eroare close");exit(1);} // close write end; process will read from pipe
 if(close(pfd2[0])<0) {perror("Eroare close");exit(1);} //close read end; write in pipe
 while (read(pfd1[0], c, 1) > 0){
    if(islower(*c))  write(pfd2[1],c,1);//writing in pipe

 }
 if(close(pfd1[0])<0) {perror("Eroare close");exit(1);} /* close other ends */ 
 if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
 if(close(pfd3[0])<0) {perror("Eroare close");exit(1);}
 if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
 exit(0); 
 } 


 //make second child
 if((pid2=fork())<0){ 
  perror("Eroare la fork"); 
  exit(1); 
 } 

 if(pid2==0){ /* second child*/ 
      if(close(pfd1[0])<0) {perror("Eroare close");exit(1);}
  if(close(pfd1[1])<0) {perror("Eroare close");exit(1);}
  if((fo=open("statistica.txt", O_CREAT | O_TRUNC | O_RDWR, 
                S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | 
                S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IROTH))==-1)
    {perror("Eroare open");exit(1);}
  if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
  letter[0][0]='A';
  letter[0][1]=0;
  while(read(pfd2[0],c,1)>0) {          
    for(i=0;i<=letternumber;i++) 
          if(letter[i][0]==*c) {letter[i][1]++;sw=1;}
    if (sw==0){
          letter[letternumber][0]=*c;
          letter[letternumber++][1]=1;
    }     
    sw=0;    
  }
  printf("\n");//why won't it write to file without it; 
                   //wihtout it, it writes to screen?
  if(close(pfd2[0])<0) {perror("Eroare close");exit(1);}
  dup2(fo,1);
  for(i=0;i<letternumber;i++) 
      printf("%c %d\n",letter[i][0],letter[i][1]);
  if(close(fo)<0) {perror("Eroare close");exit(1);}
  if(close(pfd3[0])<0) {perror("Eroare close");exit(1);} //close read end; going to write in pipe
  dup2(pfd3[1],1);
  printf("%d",letternumber);
  if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
  exit(0);
 }  

 /* parent process */ 
 if(close(pfd1[0])<0) {perror("Eroare close");exit(1);} // close read end; write in pipe
 if(close(pfd2[0])<0) {perror("Eroare close");exit(1);}
 if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
 if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}

 if((fd=open("date.txt",O_RDONLY))==-1)
  {perror("Eroare open");exit(1);}

 while(read(fd,c,1)>0)
      write(pfd1[1],c,1); //write in pipe

 if(close(pfd1[1])<0) {perror("Eroare close");exit(1);}
 //dup2(pfd3[0],0);
 while(read(pfd3[0],c,1)>0) printf("%c",*c);
 printf("\n");
 if(close(pfd3[0])<0) {perror("Eroare close");exit(1);}
 wait(&status);
 wait(&status);
}