进程之间的管道链

发布于 2024-12-25 22:33:14 字数 1966 浏览 0 评论 0原文

我想要一个父母带着两个孩子。

父进程从文件“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));

}

I want to have one parent with 2 children.

The parent reads from file "a.txt" and sends trough pipe to first child; the first child reads the chars and sends to the second child the lower letter chars.

The second child prints in "b.txt" each distinct char and number of appearances(per line) and then sends trough a pipe to the parent the number of distinct chars. The parent prints the result from the second child.

I've done the pipe from parent to 1 child and to test I've put a pipe back to the parent.
What I can't figure it out is how to make the pipe go to the second child. I've been searching for information on dup2 but I don't get on how to make it work.

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

记忆里有你的影子 2025-01-01 22:33:14

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

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) 来打印错误消息。这将为您和您的用户提供可以搜索的错误的实际原因。如果您的用户遇到 setrlimit(2) NPROC 最大进程限制、系统范围的进程限制,fork(2) 可能会失败,内核内存不足。

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) 四次< /em> -- 用于父级和子级之间的双向。如果您将管道端点存储在具有对您有意义的名称的数组中,那么它们将更容易跟踪。也许创建名为 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) 重新排列文件描述符,除非您想要执行其他程序来处理“过滤”任务。只需使用 from_parent[...]from_child[...] 描述符进行 read(2)write(2)to_child[...]to_parent[...] 描述符。

也许使用 socketpair(2) 使用 AF_UNIX 创建双向套接字,然后可以读取和写入,整个事情会更容易以与任何其他 BSD 风格套接字相同的方式。请参阅 socket(7)unix(7) 了解概述。

I have a few specific comments on your code:

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

While there is nothing wrong with this, there is also no need for this char to be allocated from the heap. The more idiomatic approach would use char c; here and then pass &c to read(2) and write(2) system calls. (Even more idiomatic would be to use the C Standard IO facility; freopen(3), getchar(3), and putchar(3) -- but do not make that transition until you have this code working exactly as you want it to, because it is an additional complication with the problem you're trying to solve.)

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

By using your own error message, you are missing out on important error information. You should use perror(3) to print an error message instead. This will give you and your users an actual cause for errors that they can search for. fork(2) can fail if your user is running into the setrlimit(2) NPROC maximum process limit, the system-wide process limit, out of kernel memory.

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

You should also check the return value from open(2) calls. (You're supposed to also check the return values from write(2) and close(2) for errors, but handling these errors is harder. Simply printing the error and quitting is a good start for most programs.)

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

This is the wrong location for the close(2) call -- you shouldn't be closing this filedescriptor over and over for every input character. If you were checking the close(2) return value, you would notice errno is set to EBADF because the file descriptor is no longer valid on the second and subsequent calls.

Now, onto the problem you came here for: the sequence of fork(), pipe(), and dup2() calls that will hook up all your processes in a pipeline and send data back to the parent process. Since pipe(2) creates uni-directional pipe(7)s, you need to call pipe(2) four times -- for both directions between parent and children. If you store the pipe endpoints in arrays with names that mean something to you, they will be easier to keep track of. Perhaps create arrays named to_ for writing into and from_ for reading 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];
}

Note that you don't actually need to use dup2(2) to re-arrange the filedescriptors unless you want to execute other programs to handle the "filter" task. Just read(2) using the from_parent[...] or from_child[...] descriptors and write(2) to the to_child[...] and to_parent[...] descriptors.

Maybe the entire thing would be easier with socketpair(2) using AF_UNIX to create bi-directional sockets, which can then be read from and written to in the same fashion as any other BSD-style socket. See socket(7) and unix(7) for an overview.

遇见了你 2025-01-01 22:33:14

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

请注意,这意味着父级将关闭子级通信管道的两个端点。该管道的每个端点都将由子管道之一使用。每个孩子还应该关闭它不使用的端点。

You do not need dup(). Simply open the pipes in the parent and then in each process close() the endpoints you don't need and just use the endpoints you do need.

Note that this means that the parent will close both endpoints of the pipe for child-child communication. Each of the endpoints of this pipe will be used by one of the children. Each child should also close the endpoint it doesn't use.

妥活 2025-01-01 22:33:14

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

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

Thank you for your answers.
Here is the code for the whole problem.

#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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文