Unix:如果进程终止,管道(半双工)会发生什么

时间:2016-05-19 06:20:17

标签: c unix pipe

我试图证明我的一个疑问,即两个不相关的进程可以共享fd半双工管道并进行通信。

我为此创建了两个程序。但后来我又提出了另一个问题,即如果进程死了会发生什么事情?因为我的读者得到了一些垃圾信息,当我打印出信息时。

作家

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int fd[2];
    char str[] = "hello\n";
    if(pipe(fd) < 0)
        perror("Pipe creation failed\n");

    //Since i am a writer, i should close the reading end as a best practice
    close(fd[0]);

    /*
    The processes need not to be related processes, in order to use the half duplex pipes. fd is just a number/identifier
    which can be shared across different processes 
    */
    printf("Hey there !!! use this file descriptor for reading : %d\n", fd[0]);

    //writing message   
    write(fd[1],str,strlen(str)+1);
    return 0;
}

阅读器

#include <stdio.h>
#include <unistd.h>

int main()
{
    int fd,bytesRead;
    char buffer[1024];

    printf("please enter the fd :");
    scanf("%d",&fd);

    bytesRead = read(fd,buffer,1024);

    printf("Bytes Read : %d\nMessage : %s\n", bytesRead, buffer);
    return 0;
}

2 个答案:

答案 0 :(得分:1)

你不能这样做。

文件描述符表是按进程的;每个进程都有自己独立的一组打开文件描述符(注意打开文件描述符,每个进程和打开文件描述之间的区别,它们是系统范围的,在open(2)中讨论过。如果要在进程之间共享文件描述符,则需要通过fork(2)继承文件描述符,或者通过unix(7)通过sendmesg(2)通过SCM_RIGHTS传递给cmesg(3)域套接字。 https://github.com/appsquickly/Typhoon/pull/503标题。

(在Linux上,你也可以将路径传递给/proc/[PID]/fd/...,而其他系统可能有自己的非便携式等价物。)

在你的情况下发生的事情是读取失败(你给它一个未打开的文件描述符),留下你的缓冲区未初始化的垃圾。由于您没有检查返回值,因此您永远不会知道它失败了。

答案 1 :(得分:0)

在管道手册页中,

pipe()创建一个管道,一个可用于进程间通信的单向数据通道。数组pipefd用于返回引用管道末端的两个文件描述符。 pipefd [0]指的是管道的读取端。 pipefd [1]指的是管道的写端。写入管道写端的数据由内核缓冲,直到从管道的读端读取。

管道主要用于相关过程(父和子)。您无法将管道用于非相关流程。

在相关过程中,一端关闭。在另一端,进程获取SIGPIPE信号。

使用管道的示例程序: -

   #include <sys/wait.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>
   #include <string.h>

   int
   main(int argc, char *argv[])
   {
       int pipefd[2];
       pid_t cpid;
       char buf;

       if (argc != 2) {
        fprintf(stderr, "Usage: %s <string>\n", argv[0]);
        exit(EXIT_FAILURE);
       }

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

       cpid = fork();
       if (cpid == -1) {
           perror("fork");
           exit(EXIT_FAILURE);
       }

       if (cpid == 0) {    /* Child reads from pipe */
           close(pipefd[1]);          /* Close unused write end */

           while (read(pipefd[0], &buf, 1) > 0)
               write(STDOUT_FILENO, &buf, 1);

           write(STDOUT_FILENO, "\n", 1);
           close(pipefd[0]);
           _exit(EXIT_SUCCESS);

       } else {            /* Parent writes argv[1] to pipe */
           close(pipefd[0]);          /* Close unused read end */
           write(pipefd[1], argv[1], strlen(argv[1]));
           close(pipefd[1]);          /* Reader will see EOF */
           wait(NULL);                /* Wait for child */
           exit(EXIT_SUCCESS);
       }
   }

上面的程序创建一个管道,然后fork(2)来创建一个子进程;子进程继承了一组引用同一管道的重复文件描述符。在fork(2)之后,每个进程都会关闭管道不需要的描述符(参见管道(7))。然后父进程将程序命令行参数中包含的字符串写入管道,子进程一次从管道读取该字符串,并在标准输出上回显它。