1.概述

管道是最初的Unix IPC通信,可追溯到1973年的Unix第三版。尽管对于许多操作来说很有用,但它们的根本局限于没有名字,只能由亲缘关系的进程使用。这一点随着FIFO的加入System III Unix中得以改正。FIFO有时候称为命令管道(named pipe)。管道和FIFO都是使用通常的read和write函数访问的。
从技术上讲,自从可以在进程间传递描述符后,管道也能用于无亲缘关系的进程间。然而通常的说,管道通常用于具有共同祖先的进程间通信。

1.1管道的特点

(1)只能用于具有共同祖先的进程(具有亲缘关系的进程)之间通信,当然除了命名管道,命名管道有一个路径名与之关联,命名管道允许无亲缘关系的进程访问同一个FIFO;通常,一个管道由一个进程创建,然后该进程调用fork,此后,父子进程之间就可应用该管道 
(2)管道的进程间通信是基于字节流的 
(3)管道是基于文件形式的,自带同步互斥机制,并且只能进行单向传输 
(4)一般而言,进程退出,管道释放,所以管道的生命周期是随进程的

2.管道

所有样式的Unix提供管道。它由pipe函数创建,提供一个单路(单向)数据流。
调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过pipefd参数传出给用户程序两个文件描述符,pipefd[0]指向管道的读端,fpipefd[1]指向管道的写端。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。

3.管道实现进程间通信

开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信。

3.1单个进程中的管道

   
父进程调用pipe函数创建管道,得到两个文件描述符fd[0]、fd[1]指向管道的读端和写端。父进程中可以通过管道一方写入数据,父进程也可以通过管道的另一方读取数据,上图很好的说明了当个进程中的管道通信方式。

3.2 父进程fork出子进程

管道的经典用途是以下方式为两个不同进程(一个是父进程一个是子进程)提供进程间通信手段。首先,由一个进程)(它将成为父进程)创建一个管道后调用fork派生一个自身的副本,如下图所示:
父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。那么这样在父进程和子进程中都有两个文件描述符分别指向管道的写端和读端。父进程和子进程都能对管道进行读写操作。

3.3 父进程关闭fd[0] 子进程关闭fd[1]

父进程关闭在这个管道的读出端fd[0],子进程关闭这个管道的写入端fd[1]。这就在父进程和子进程之间提供了一个单向数据流。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。

3.4 代码实现管道通信

子进向父进程发送数据
#include <stdio.h>
#include <unistd.h>
#include <string.h>int main()
{int fd[2];if (pipe(fd)){perror("pipe");return 1;}// 实现父进程写,子进程读pid_t id = fork();if (id < 0){perror("fork");return 2;}else if (id == 0) // child{close(fd[1]);char buf[128];int cnt = 0;while (cnt++ < 5){ssize_t _s = read(fd[0], buf, sizeof(buf));if (_s > 0){buf[_s] = '\0';;printf("father say to child: %s\n", buf);}else if (_s == 0){printf("father close write");break;}else{perror("read");break;}}close(fd[0]);}else        // father{close(fd[0]);char * msg = "hello world";int cnt = 0;while (cnt++ < 5){write(fd[1], msg, strlen(msg));sleep(1);}close(fd[1]);}return 0;
}

3.命名管道(FIFO)

管道没有名字,因此它们的最大的劣势就是只能用于有一个共同祖先进程的各个进程之间的通信。我们无法在无亲缘关系的两个进程之间创建一个管道并将它作为IPC通道(不考虑描述符的传递)。管道的缺点就是只能在有亲缘关系的进程间进行通信,针对这个缺陷,又提出来了命名管道(FIFO)的概念。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。命名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。
FIFO指的就是先进先出(first in,first on),Unix中的FIFO类似管道。他是一个单向(半双工)的数据流。不同于管道的是,每个FIFO有一个路径与之相连,从而允许无亲缘关系之间的进程访问同一个FIFO。FIFO也称为有名管道(named pipe)。
FIFO通过mkfifo函数创建
其中pathname是一个普通的Unix路径名,它是该FIFO的名字。
mode参数指的是文件权限位,类似于open的第二个参数。mkfifo命令也能创建FIOF。可以从shell脚本或者命令行中使用它。在创建一个FIFO后,它必须或者打开来读或者来写,所用的可以是open函数,也可以是某个标准I/O打开函数,列如fopen。FIOFU不能打开来既可以读又可以写,因为他是半双工的。对管道或者FIFO的write总是向末尾添加数据,对他们的read总是从开头添加数据。如果对管道或者FIFO调用lseek,这就返回错误。

3.1FIFO两个属性

1、FIFO是一个设备文件,在文件系统中以文件名的形式存在,因此即使进程与创建FIFO的进程不存在血缘关系也依然可以通信,前提是可以访问该路径。 
2、FIFO(first input first output)总是遵循先进先出的原则,即第一个进来的数据会第一个被读走。

3.2 代码实现命令管道通信

server向命令管道中发送数据
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{// 创建管道时需要在mode参数位置传S_IFIFO,表明创建的是命名管道int ret = mkfifo("./.fifo", S_IFIFO | 0644);  if (ret < 0){perror("mkfifo");return 1;}int fd = open("./.fifo", O_WRONLY);if (fd < 0){perror("open");return 2;}int cnt = 0;char *msg = "hello world";while (cnt++ < 5){write(fd, msg, strlen(msg));sleep(1);}close(fd);return 0;
}
client向命令管道中接收数据
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{int fd = open("./.fifo", O_RDONLY);if (fd < 0){perror("open");return 2;}int cnt = 0;char buf[128];while (cnt++ < 5){ssize_t _s = read(fd, buf, sizeof(buf) - 1);if (_s > 0){buf[_s] = '\0';;printf("server say to client: %s\n", buf);}else if (_s == 0){printf("server close write\n");break;}else{perror("read");}sleep(1);}close(fd);return 0;
}

4. 命令管道和管道的区别

命名管道创建完成后就可以使用,其使用方法与管道一样; 
区别在于: 
(1)命名管道使用之前需要使用open()打开。这是因为:命名管道是设备文件,它是存储在硬盘上的,而管道是存在内存中的特殊文件。 
(2)但是需要注意的是,命名管道调用open()打开有可能会阻塞,但是如果以读写方式(O_RDWR)打开则一定不会阻塞; 
(3)命名管道以只读(O_RDONLY)方式打开时,调用open()的函数会被阻塞直到有数据可读; 
(4)命名管道如果以只写方式(O_WRONLY)打开时同样也会被阻塞,知道有以读方式打开该管道。

进程间的通信方式(二):管道Pipe和命令管道FIFO相关推荐

  1. 进程间的通信方式(1)

    程序员必须让拥有依赖关系的进程集协调,这样才能达到进程的共同目标.可以使用两种技术来达到协调.第一种技术在具有通信依赖关系的两个进程间传递信息.这种技术称做进程间通信(interprocess com ...

  2. step4 . day7 进程间的通信方式

    进程间的通信方式: 无名管道(pipe) 有名管道 (fifo) 信号(signal) system v5的进程间通信方式 共享内存(share memory) 消息队列(message queue) ...

  3. unix进程间的通信方式

    unix进程间的通信方式 (1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信. (2)命名管道(named pipe):命名管道克服了管道 ...

  4. 1、几种进程间的通信方式

    1.几种进程间的通信方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named ...

  5. msgget();msgsnd();msgrcv();msgctl(); 消息队列 Linux进程间的通信方式之消息队列

    Linux进程间的通信方式 ----消息队列. 消息队列和共享内存类似 消息队列它允许一个或多个进程向它写消息,一个或多个进程向它写读消息. 消息队列存在于系统内核中,消息的数量受系统限制. 我们来看 ...

  6. 共享内存(进程间的通信方式)

    目录 1.共享内存的特点 2.函数接口 3.有关共享内存的系统命令 1.共享内存的特点 (1)共享内存是一种最高效的进程间的通信方式,进程可以直接读写内存,而进程之间不需要通过任何数据的拷贝. (2) ...

  7. Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

    整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道 ...

  8. 进程间的通信方式(管道,消息队列,共享内存,信号)

    目录 了解 使用管道来通信 无名管道 有名管道 消息队列 key 键值生成 共享内存 信号 信号概述 信号如何携带消息 信号发送函数: 信号量 了解 创建进程后实现父子通讯的连接. 我们希望有一个管道 ...

  9. Linux 进程 | 进程间的通信方式

    文章目录 管道 匿名管道 pipe 命名管道 FIFO 共享内存 共享内存的使用流程: 消息队列 信号量 套接字 在之前的博客中讲过,虚拟空间出现的其中一个目的就是解决 进程没有独立性,可能访问同一块 ...

最新文章

  1. [MATLAB调试笔记]Update magnetic field in one step
  2. scala 去除重复元素_Scala程序从列表中删除重复项
  3. springboot幂等性_SpringBoot+Redis实现接口幂等性,就看这篇了
  4. js获取当前时间戳,仿PHP函数模式
  5. python中列表操作
  6. C# 读书笔记之访问虚方法、重写方法和隐藏方法
  7. 内存一致性模型(Memory Consistency Models)
  8. 最新声音鉴定鉴卡引流神器PHP源码
  9. IOS AirPrint功能
  10. 平差的理解及一种最简单的高斯马尔科夫模型(Gauss Markov Model)
  11. 计算机水平cet2是什么等级,英语cet2等级考试试题
  12. 实验二 译码器及其应用
  13. Win10家庭版安装软件时提示“为了对电脑进行保护,已经阻止此应用”
  14. 【板栗糖GIS】联想win11如何解决浏览器edge默认页面无法修改的问题
  15. node.js(二 --- events 、buffer、)
  16. iPhone忘记访问限制密码的解决方案
  17. Qt笔记(十五)之设置程序图标
  18. 不定宽高,实现盒子左右垂直居中
  19. JSoup模拟登录新版正方教务系统(内网-教务系统)获取信息过程详解
  20. 使用关键字like进行模糊查询

热门文章

  1. 代码规范之华为公司代码规范
  2. java应用之solr入门篇
  3. windows下安装composer方法
  4. 55种网页常用小技巧
  5. Mysql在大型网站的应用架构演变
  6. SQL pivot与unpivot 实现的简单的:行转列及列转行
  7. SharePoint中Tab方式进行内容展现的WebPart
  8. 存储过程中将sql语句结果赋值给变量
  9. 详解C中volatile关键字
  10. 关于程序中的操作符左移和右移问题