进程间的通信方式——1、管道(pipe)

原创 2018年04月17日 14:04:03

1.进程间通信

   每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信。
  • 1
  • 2

这里写图片描述

不同进程间的通信本质:进程之间可以看到一份公共资源;而提供这份资源的形式或者提供者不同,造成了通信方式不同,而 pipe就是提供这份公共资源的形式的一种。

2.匿名管道

2.1管道的创建

   管道是由调用pipe函数来创建
  • 1
  • 2
#include <unistd.h>
int pipe (int fd[2]);
                         //返回:成功返回0,出错返回-1     
  • 1
  • 2
  • 3
 fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。
  • 1
  • 2

2.2管道如何实现进程间的通信

(1)父进程创建管道,得到两个⽂件描述符指向管道的两端

(2)父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。

(3)父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。
这里写图片描述

2.3如和用代码实现管道通信

  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <string.h>  
  4. #include <errno.h>  
  5. int main()  
  6. {  
  7.     int fd[2];  
  8.     int ret = pipe(fd);  
  9.     if (ret == -1)  
  10.     {  
  11.         perror(”pipe error\n”);  
  12.         return 1;  
  13.     }  
  14.     pid_t id = fork();  
  15.     if (id == 0)  
  16.     {//child  
  17.         int i = 0;  
  18.         close(fd[0]);  
  19.         char *child = “I am  child!”;  
  20.         while (i<5)  
  21.         {  
  22.             write(fd[1], child, strlen(child) + 1);  
  23.             sleep(2);  
  24.             i++;  
  25.         }  
  26.     }  
  27.     else if (id>0)  
  28.     {//father  
  29.         close(fd[1]);  
  30.         char msg[100];  
  31.         int j = 0;  
  32.         while (j<5)  
  33.         {  
  34.             memset(msg,’\0’,sizeof(msg));  
  35.             ssize_t s = read(fd[0], msg, sizeof(msg));  
  36.             if (s>0)  
  37.             {  
  38.                 msg[s - 1] = ’\0’;  
  39.             }  
  40.             printf(”%s\n”, msg);  
  41.             j++;  
  42.         }  
  43.     }  
  44.     else  
  45.     {//error  
  46.         perror(”fork error\n”);  
  47.         return 2;  
  48.     }  
  49.     return  0;  
  50. }  

运行结果:

每隔2秒打印一次I am child!        并且打印了五次。
  • 1
  • 2

这里写图片描述

2.4管道读取数据的四种的情况

(1)读端不读,写端一直写
这里写图片描述
(2)写端不写,但是读端一直读
这里写图片描述

(3)读端一直读,且fd[0]保持打开,而写端写了一部分数据不写了,并且关闭fd[1]。
这里写图片描述

如果一个管道读端一直在读数据,而管道写端的引⽤计数⼤于0决定管道是否会堵塞,引用计数大于0,只读不写会导致管道堵塞。

(4)读端读了一部分数据,不读了且关闭fd[0],写端一直在写且f[1]还保持打开状态。

这里写图片描述

  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <string.h>  
  4. #include <errno.h>  
  5. int main()  
  6. {  
  7.     int fd[2];  
  8.     int ret = pipe(fd);  
  9.     if (ret == -1)  
  10.     {  
  11.         perror(”pipe error\n”);  
  12.         return 1;  
  13.     }  
  14.     pid_t id = fork();  
  15.     if (id == 0)  
  16.     {//child  
  17.         int i = 0;  
  18.         close(fd[0]);  
  19.         char *child = “I am  child!”;  
  20.         while (i<10)  
  21.         {  
  22.             write(fd[1], child, strlen(child) + 1);  
  23.             sleep(2);  
  24.             i++;  
  25.         }  
  26.     }  
  27.     else if (id>0)  
  28.     {//father  
  29.         close(fd[1]);  
  30.         char msg[100];  
  31.         int status = 0;  
  32.         int j = 0;  
  33.         while (j<5)  
  34.         {  
  35.             memset(msg, ’\0’sizeof(msg));  
  36.             ssize_t s = read(fd[0], msg, sizeof(msg));  
  37.             if (s>0)  
  38.             {  
  39.                 msg[s - 1] = ’\0’;  
  40.             }  
  41.             printf(”%s  %d\n”, msg, j);  
  42.             j++;  
  43.         }  
  44.         //写方还在继续,而读方已经关闭它的读端  
  45.         close(fd[0]);  
  46.         pid_t ret = waitpid(id, &status, 0);  
  47.         printf(”exitsingle(%d),exit(%d)\n”, status & 0xff, (status >> 8) & 0xff);  
  48.         //低八位存放该子进程退出时是否收到信号  
  49.         //此低八位子进程正常退出时,退出码是多少  
  50.     }  
  51.     else  
  52.     {//error  
  53.         perror(”fork error\n”);  
  54.         return 2;  
  55.     }  
  56.     return  0;  
  57. }  

运行结果:

这里写图片描述

使用kill -l 查看13号信号,可以知道13号信号代表SIGPIPE。

总结:
如果一个管道的写端一直在写,而读端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只写不读再次调用write会导致管道堵塞;
如果一个管道的读端一直在读,而写端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只读不写再次调用read会导致管道堵塞;
而当他们的引用计数等于0时,只写不读会导致写端的进程收到一个SIGPIPE信号,导致进程终止,只写不读会导致read返回0,就像读到⽂件末尾⼀样。

2.5管道特点

1.管道只允许具有血缘关系的进程间通信,如父子进程间的通信。

2.管道只允许单向通信。

3.管道内部保证同步机制,从而保证访问数据的一致性。

4.面向字节流

5.管道随进程,进程在管道在,进程消失管道对应的端口也关闭,两个进程都消失管道也消失。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2.6管道容量大小

测试管道容量大小只需要将写端一直写,读端不读且不关闭fd[0],即可。
测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main()
{
    int fd[2];
    int ret = pipe(fd);
    if (ret == -1)
    {
        perror("pipe error\n");
        return 1;
    }
    pid_t id = fork();
    if (id == 0)
    {//child
        int i = 0;
        close(fd[0]);
        char *child = "I am  child!";
        while (i++)
        {
            write(fd[1], child, strlen(child) + 1);
            printf("pipe capacity: %d\n", i*(strlen(child) + 1));
        }
        close(fd[1]);
    }
    else if (id>0)
    {//father
        close(fd[1]);
        waitpid(id, NULL, 0);
    }
    else
    {//error
        perror("fork error\n");
        return 2;
    }
    return  0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

可以看到写到65520之后管道堵塞了,而65520即为64K大小即为管道的容量。
这里写图片描述

进程间通信方式———信号量(Semaphore)
http://blog.csdn.net/skyroben/article/details/72513985

进程间通信方式———消息队列
http://blog.csdn.net/skyroben/article/details/72520501

进程间通信方式——共享内存
http://blog.csdn.net/skyroben/article/details/72625028

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Windgs_YF/article/details/79973959

进程间的通信方式——pipe(管道)

详解进程间通信方式———管道;管道是如何实现进程间通信的;以及管道读取数据的四种方式,以及管道容量的大小。...
  • skyroben
  • skyroben
  • 2017-05-10 00:43:13
  • 7091

运用管道(pipe)进行进程间通信

   在linux系统中,管道是一种特殊的文件,它的主要作用是实现进程间的通信。    管道的一个显著特点是:当一个管道建立后,将获得两个文件描述符,分别用于对管道读取和写入...
  • mazheng1989
  • mazheng1989
  • 2012-03-11 14:46:57
  • 736

进程间通信-管道(PIPE)和有名管道(FIFO)

前面我们学习了一下进程,我们知道多,进程间的地址空间相对独立。进程与进程间不能像线程间通过全局变量通信。 如果想进程间通信,就需要其他机制。          常用的进程间通信方式有这...
  • w616589292
  • w616589292
  • 2016-03-22 18:52:34
  • 2750

进程间通信:管道(pipe)

管道的概述 管道也叫无名管道,它是是 UNIX 系统 IPC(进程间通信) 的最古老形式,所有的 UNIX 系统都支持这种通信机制。 无名管道有如下特点: 1、半双工...
  • lianghe_work
  • lianghe_work
  • 2015-08-16 23:19:43
  • 4703

Linux进程通信(一)——pipe管道

本章内容 采用pipe管道如何进行进程之间的通信 pipe管道进程通信的规则和限制 Linux中pipe管道的实现机制和管理pipe管道的结构体 什么是进程通信进程通信就是两个进程之间进行数据交换,在...
  • bit_clearoff
  • bit_clearoff
  • 2017-02-14 20:30:29
  • 1475

C++ 进程间的通讯(一):简单的有名管道实现

进程间的通讯(一):简单的有名管道实现 一 管道简介 命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是命名管道可以在不相关的进程...
  • u010797208
  • u010797208
  • 2014-11-28 02:09:55
  • 7914

【C语言】【unix c】如何使用管道实现两个进程间的通信

【C语言】【unix c】如何使用管道实现两个进程间的通信
  • weixin_38239856
  • weixin_38239856
  • 2017-08-31 22:36:07
  • 230

管道通常用在两个线程间通信或进程间通信

管道,信号量,共享内存,socket的实际使用场景和NSPipe管道的使用 找了很久也没有找到NSPipe在IOS方面的常规使用()。我试了半天终于找到它的正常的使用方法,我想对很多想使用管...
  • bravegogo
  • bravegogo
  • 2016-06-01 16:42:08
  • 2136

4种进程间通信方式详解

进程间通信有4种方式,以下从简单到复杂的方式出场: 1.管道(pipe)     管道是一种具有两个端点的通信通道,一个管道实际上就是只存在在内存中的文件,对这个文件操作需要两个已经打开文件进行,...
  • u014673901
  • u014673901
  • 2016-04-07 21:09:27
  • 17094

进程间通信之管道篇

何为进程间通信 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都是看不到的。所以进程之间如果要交换数据就必须通过内核。 在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核...
  • qq_33724710
  • qq_33724710
  • 2016-08-28 14:22:55
  • 806
收藏助手
不良信息举报
您举报文章:进程间的通信方式——1、管道(pipe)
举报原因:
原因补充:

(最多只允许输入30个字)