Liunx进程间通信之管道

目录

管道(pipe)

管道的局限性:

管道的创建:  

fork使用管道使父子进程进行通信

编程实现

运行结果

运行结果分析


  • 管道(pipe)

管道是UNIX系统IPC的最古老的形式,所有的UNIX系统都提供此种通信机制。管道的实质是一个内核缓冲区,进程以先进 先出(FIFO, First In First Out)的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺 序地读取数据,该缓冲区可以看做一个循环队列,读和写的位置都是自动增加的,一个数据只能被读一次,读出以后再缓冲区都 不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或写进程是否进入等待队列,当空的缓冲区有新数据写 入或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。

  • 管道的局限性:

  1. 半双工,数据只能在一个方向流动,现在有些系统可以支持全双工管道,但是为了最佳的可移植性,应认为系统 不支持全双工管道; (

  2. 管道只能在具有公共祖先之间的两个进程之间使用;

  • 管道的创建:  

管道可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不 属于其他任何文件系统,并且只存在于内存中。管道是通过调用pipe函数创建的。

#include <fcntl.h>              
#include <unistd.h>

int pipe2(int pipefd[2], int flags);

经由参数fd返回的两个文件描述符:fd[0]为读而打开,fd[1]为写而打开,fd[1]的输出是fd[0]的输入。

  • fork使用管道使父子进程进行通信

通常,进程会先调用pipe,接着调用fork,从而创建了父进程与子进程的IPC通道。


 

fork之后做什么取决于我们想要的数据流的方向,例如:对于从父进程到子进程,父进程关闭管道的读端fd[0],子进程关闭写端 fd[1]。

父进程关闭读端,子进程关闭写端,这样就实现了父子进程间的通信。子进程从管道的fd[0]写入数据,父进程从管道的fd[1]读数据。

  • 编程实现

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define  BUF_SIZE   1024
#define  W_STR      "Hello child, I'am praent."
int main(int argc, char *argv[])
{
    int       pipe_fd[2];
    int       pid;
    char      buf[BUF_SIZE];
    int       wait_status;
    int       rv;

    if (pipe(pipe_fd) < 0) //使用管道
    {
        printf("Piep error: %s\n", strerror(errno));
        return -1;
    }

    pid = fork();  //fork 创建子进程
    if (pid <0)
    {
        printf("Fork error: %s\n", strerror(errno));
        return -2;
    }
    else if (pid > 0)  //父进程
    {
        close(pipe_fd[0]);  //关闭读端
        if ((rv =write(pipe_fd[1], W_STR, sizeof(W_STR)))< 0) //从管道写入数据
        {
            printf("The parent write by pipe_fd[%d] error: %s\n",pipe_fd[1], strerror(errno));
            return -3;
        }
        printf("The parent write %d bytes form pipe_fd[%d] to pipe_fd[%d].\n",rv, pipe_fd[1], pipe_fd[0]);
        wait(wait_status);  //等待子进程结束

        puts("The parent wait child exit and will exit.");
    }
    else if (0 == pid)  //子进程
    {
        close(pipe_fd[1]);  //关闭写端
        memset(buf, 0, BUF_SIZE);

        if ((rv =read(pipe_fd[0], buf, sizeof(buf))) <0)  //从管道读数据
        {
            printf("Read form pipe_fd[%d] error: %s\n", pipe_fd[0],strerror(errno));
            return -4;
        }
        printf("The child read %d bytes form pipe_fd[%d],there are:\n%s.\n", rv, pipe_fd[0],buf);

        puts("The child will go to exit...");
        sleep(1);
        return 0;
    }


    return 0;
}

  • 运行结果

  • 运行结果分析

父进程创建管道之后fork(),这时子进程会继承父进程所有打开的 文件描述符(包括管道),这时对于一个管道就有4个读写端(父子进程各有一对管道读写端),如果需要父进程往子进程里写 数据,则需要在父进程中关闭读端,在子进程中关闭写端;而如果需要子进程往父进程中写数据,则可以在父进程关闭写端,然 后子进程中关闭读端。

这样就使得父进程写数据,子进程读数据,实现父子进程间的通信。

发布了47 篇原创文章 · 获赞 37 · 访问量 3689

猜你喜欢

转载自blog.csdn.net/qq_44045338/article/details/104964323