进程间通信之无名管道和有名管道


  无名管道(匿名管道)和有名管道(命名管道)是Linux系统内核的特殊文件,用于进程之间的通信。

一、无名管道

1.什么是无名管道

    无名管道(匿名管道)的实质是一个内核缓冲区,进程以先进先出(FIFO, First In First Out)的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺序地读取数据,该缓冲区可以看做一个循环队列,读和写的位置都是自动增加的,一个数据只能被读一次,读出以后再缓冲区都不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或写进程是否进入等待队列,当空的缓冲区有新数据写入或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。
   无名管道相当于一个队列结构,fd[1]为写入端(入队),fd[0]为读出端(出队)。其中信息读出后即删除,再次读取时即为下一个信息。无名管道通过调用pipe()函数创建, 通过操作fd[1]写入信息,操作fd[0]读取信息。只有具有亲缘关系(有共同的祖先进程)的进程间才可以通过此管道进行通信。
在这里插入图片描述

2.局限性

这里有两个局限性:
① 管道是半双工的, 我们可以通过建立两个管道来实现全双工。
在这里插入图片描述
管道的数据流方向取决于程序员

  • 需要写入则进程关闭读取的文件描述符,如果管道的另一端关闭了读的文件描述符,此时写入信息会产生SIGPIPE信号,系统默认程序退出,可以根据自己需求捕捉此信号。

    连接建立后,若某一端关闭连接,而另一端仍然向它写数据,第一次写数据后会收到RST响应,此后再写数据,内核将向进程发出SIGPIPE信号,通知进程此连接已经断开。SIGPIPE信号的默认处理是终止程序。

  • 需要读取则关闭写入的文件描述符,在管道所有的数据被读取后,read()函数会返回0, 表示文件结束。 数据读取走后,便不在管道中,在没有读取到之前, read()函数会一直阻塞。

② 无名管道只能支持具有亲缘关系的进程间通信, 我们后面可以通过命名管道解决此问题。

3.pipe()函数

       #include <unistd.h>

       int pipe(int pipefd[2]); 
       //成功返回0, 失败返回-1并将返回错误信息errno
       //pipefd[0]为读端,pipefd[1]为写端 

在调用pipe()函数成功后,创建内核缓冲区(也就是管道),不需要手动open()打开,会返回读端pipefd[0]、写端pipefd[1]两个文件描述符,但是需要手动close()关闭。

4.流程图

在这里插入图片描述

5.例程

/*********************************************************************************
 *      Copyright:  (C) 2020 Qiuliang<comeonqiuliang@163.com>
 *                  All rights reserved.
 *
 *       Filename:  test_pipe_2.c
 *    Description:  This file is test of pipe 
 *                 
 *        Version:  1.0.0(2020年04月09日)
 *         Author:  Qiuliang <comeonqiuliang@163.com>
 *      ChangeLog:  1, Release initial version on "2020年04月09日 17时40分50秒"
 *                 
 ********************************************************************************/

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


#define	        WORLD           "我是你爸爸!"			/*  */

int         g_run = 0;

void do_pipe(int signal)
{
   
    if(SIGPIPE == signal)
    {
   
        printf("管道读端关闭, 一秒后退出。\n");
        sleep(1);
        g_run = 1;
    }
}//读端关闭执行此程序

int main(int argc, char *argv[])
{
   
    int                 ppfd[2];
    int                 pid = -1;
    int                 rv = -1;
    int                 i=0;
    int                 fork_status;//储存子进程状态
    char                buf[1024];

    if(pipe(ppfd) < 0)//创建管道
    {
   
        printf(
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值