如何多次写入/读取管道

Posted

技术标签:

【中文标题】如何多次写入/读取管道【英文标题】:How to write/read multiple times to a pipe 【发布时间】:2015-06-17 18:36:49 【问题描述】:

我试图让两个子进程通过管道相互通信。第一个孩子必须写数据 1 和数据 2,然后第二个孩子写数据 3 和数据 4。然后孩子们互相读取数据并打印它们.这是我到目前为止的代码。它只显示孩子们相互发送的第一条消息,然后挂起。

#include <stdio.h>
#include <sys/types.h>


int main(void) 

    pid_t child_a, child_b;
    int pipe_a[2],pipe_b[2];
    char mesazhi1[] = "First message";
    char mesazhi2[] = "Second message";

    char buf[50];

    int first_pipe = pipe(pipe_a);
    int second_pipe = pipe(pipe_b);

    if(first_pipe == -1 || second_pipe == -1 )
        perror("pipe");
        exit(1);
    

    child_a = fork();

    if (child_a == 0) 
        /* Child A code */

        printf("%s\n","the first child is writing to pipe a" );
        write(pipe_a[1],mesazhi1, sizeof(mesazhi1));
        write(pipe_a[1],mesazhi2,sizeof(mesazhi2));

        while( read(pipe_b[0],buf,sizeof(buf) + sizeof(buf) ) > 0 )
              printf("Reading from buffer for child 1 gives:  %s \n",buf);
        

     else 
        child_b = fork();

        if (child_b == 0) 
            /* Child B code */

            printf("%s\n","the second child is writing to pipe b" );
            write(pipe_b[1],mesazhi2,sizeof(mesazhi2));



            while( read(pipe_a[0],buf,sizeof(buf) +sizeof(buf) ) > 0 )
                printf("Reading from buffer for child 2 gives: %s \n",buf);
            
            write(pipe_b[1],mesazhi1,sizeof(mesazhi1));



            printf("%s\n","the second child reads data from pipe a" );


         else 
            /* Parent Code */

            int returnStatusA,returnStatusB;    
            waitpid(child_a, &returnStatusA, 0);  // Parent process waits here for child to terminate.
            waitpid(child_b, &returnStatusB, 0);  // Parent process waits here for child to terminate.


            if (returnStatusA == 0 && returnStatusB == 0)  // Verify child process terminated without error.  
            
               printf("%s\n", "The child processes terminated normally.\n"); 
            

            if (returnStatusA == 1 && returnStatusB == 1)      
            
               printf("%s\n", "The child processes terminated with an error!. \n" );    
            



            printf("%s\n","The parent terminates two childs");
        
    

【问题讨论】:

我不能说我已经做了详细的检查,但是当你完成写入和读取后,在管道文件描述符上尝试close()。这可能是一个缓冲问题。 啊,挂了。你真的应该在问题中提到这一点。 @cdarke ,我编辑了我的问题,所以它说它挂起。是否可以在一个管道中写入多个数据然后读取它们? 两个进程都试图同时读取。 可能有多个进程在读写。但是你必须在你的代码中非常清楚地知道在任何给定时刻谁在写谁在读。如果您在“A”中的管道上调用 read(),它将阻塞对 read() 的调用并且不执行任何其他操作,直到“B”写入管道并为“A”提供一些数据以读取。反之亦然。在很多程序中,这已经足够了。如果您不知道数据何时到达并且需要在等待时执行某些操作,则可以在 read() 之前使用 select() 检查管道上是否存在数据。 【参考方案1】:

您的代码导致死锁

您以错误的方式使用read() 函数。 read(pipe_a[0],buf,sizeof(buf) +sizeof(buf) )

您希望缓冲区大小增加一倍,并希望在缓冲区中放入该数量的字节。所以子 A 中的 read 等待 pipe_b ,反之亦然。因此,孩子 B 不能写信给pipe_b,因为它正在等待。同样,孩子 A 不能写信给 pipe_a,因为它正在等待。

此外,您的代码与您在问题中解释的场景不同。在孩子 B 中,您在阅读后写作。

最后使用strlen() 代替sizeof 来计算字符串的长度。

#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

int main(void) 

    pid_t child_a, child_b;
    int pipe_a[2],pipe_b[2];
    char mesazhi1[] = "First message";
    char mesazhi2[] = "Second message";

    char buf[50];

    int first_pipe = pipe(pipe_a);
    int second_pipe = pipe(pipe_b);

    if(first_pipe == -1 || second_pipe == -1 )
        perror("pipe");
        exit(1);
    

    child_a = fork();

    if (child_a == 0) 
        /* Child A code */

        printf("%s\n","the first child is writing to pipe a" );
        write(pipe_a[1],mesazhi1, strlen(mesazhi1) + 1);
        write(pipe_a[1],mesazhi2, strlen(mesazhi2) + 1);

        read(pipe_b[0], buf, strlen(mesazhi1) + 1);
        printf("Reading from buffer for child 1 gives:  %s \n",buf);        
        read(pipe_b[0], buf, strlen(mesazhi2) + 1);
        printf("Reading from buffer for child 1 gives:  %s \n",buf);        

     else 
        child_b = fork();

        if (child_b == 0) 
            /* Child B code */

            printf("%s\n","the second child is writing to pipe b" );


            read(pipe_a[0],buf, strlen(mesazhi1) + 1);
            printf("Reading from buffer for child 2 gives:  %s \n",buf);            
            read(pipe_a[0],buf, strlen(mesazhi2) + 1);
            printf("Reading from buffer for child 2 gives:  %s \n",buf);            

            write(pipe_b[1],mesazhi1, strlen(mesazhi1) + 1);
            write(pipe_b[1],mesazhi2, strlen(mesazhi2) + 1);


            printf("%s\n","the second child reads data from pipe a" );


         else 
            /* Parent Code */

            int returnStatusA,returnStatusB;    
            waitpid(child_a, &returnStatusA, 0);  // Parent process waits here for child to terminate.
            waitpid(child_b, &returnStatusB, 0);  // Parent process waits here for child to terminate.


            if (returnStatusA == 0 && returnStatusB == 0)  // Verify child process terminated without error.  
            
               printf("%s\n", "The child processes terminated normally.\n"); 
            

            if (returnStatusA == 1 && returnStatusB == 1)      
            
               printf("%s\n", "The child processes terminated with an error!. \n" );    
            



            printf("%s\n","The parent terminates two childs");
        
    

【讨论】:

所以我对函数读取进行了更改,而且我在读取之前将我的写入函数调用放在子 B 中,它仍然挂起。我认为问题出在读取原因时我放了中断while 循环程序完成执行 我稍微更改了您的代码并将其添加到我的答案中。它有效。

以上是关于如何多次写入/读取管道的主要内容,如果未能解决你的问题,请参考以下文章

如何写入命名管道而不等待读取管道

如何阻止管道中的写入,直到读取发生? (在 C 中)

多次分叉后写入管道不起作用

如何在 C# .NET 中保持 TCP 连接打开并执行多次写入/读取?

node 文件操作 读取,写入 目录的写入读取 文件流 写入流 管道流 压缩 解压

在断开连接之前等待读取命名管道