进程间通信之管道
来源:互联网 发布:哲学视频讲座视频知乎 编辑:程序博客网 时间:2024/05/22 15:39
星期三, 13. 十二月 2017 06:34下午
本篇博客主要讲解用于进程间通信的匿名管道和命名管道
参考资料:UNIX环境高级编程
邮箱:blbagony@163.com
匿名管道
#include <unistd.h> int pipe(int pipefd[2]); //成功返回 0,失败返回 -1
经由 pipefd 返回的两个文件描述符,pipefd[0] 为读而打开,pipefd[2]为写而打开
管道的五个特性
- (匿名管道)适用于有血缘关系的进程(命名管道可以满足无血缘关系的两个进程通信)
- 管道提供流式服务,即面向字节流
- 半双工,即单向通信,如果想要实现全双工就创建两个管道
- 管道的生命周期随进程,即进程结束,管道文件资源随即被系统释放
- 自带同步与互斥机制(如果管道写满了就不能在写,如果管道里尝试读管道的进程就会阻塞)进程 A 在往管道中写的时候进程 B 就不能读取管道之中的数据,进程 B 在读取管道数据的时候,进程 A 就不能在往管道中写数据。
单个进程中的管道几乎没有作用,通常调用 pipe 的进程接着调用 fork,这样就创建了父进程到子进程的 IPC 通道。
测试 Ubuntu 中管道的大小
让父进程一直往管道中写书据,而不让子进程读数据(子进程 sleep),打印管道当前管道被写入多少数据
管道的大小 645536 单位是字节
测试代码
具体使用
现在模拟一个情况,父进程网管道里写数据所以父进程需关闭读端。子进程从管道里读书据所以关闭写端管道适用于有血缘关系的进程,就这样父进程一直写,子进程一直读,管道的单向通信。我们可以发现子进程每次写完后敲下回车键,这时父进程才可以从管道中读取数据,这就是自带同步机制,父进程每次调用 write 往管道中写数据是以字节为单位,子进程调用 read 从管道里取数据同样以字节为单位这就是管道的面向字节流服务 。当程序结束后管道随即被操作系统释放,管道随进程。
使用代码
几种特殊情况
注意,这是在进程 A 和进程 B 有血缘关系的情况下。
1. 当进程 A 一直往管道中写数据,进程 B 却一直不读数据,当管道被写满后,进程 A 将被阻塞,直到进程 B 将管道中的数据读走。。
当进程 A 不向管道中写数据,进程 B 一直从管道中取数据,此时进程 B 被阻塞,很容易理解,管道中没有数据,进程 B 如何读。
当进程 A 往管道中写数据,此时操作系统如果发现读管道的文件描述符都已关闭,则操作系统会给 A 进程发送 SIGPIP 信号,默认动作是退出。
当进程 B 从管道中读数据,此时操作系统如果发现往管道写数据的文件描述符都已关闭,此时进程 B 将读到文件结束符。
命名管道
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); //成功返回 0,失败返回 -1
pathname 创建的文件为管道文件,mode 指定文件权限
一旦已经使用 mkfifo 创建了一个 FIFO,就可以使用 open 打开它。其次,一般的文件 I/O 函数(close, read, write, unlink等)都可用于 FIFO。
当打开一个 FIFO 时,非阻塞标志(O_NOBLOCK)产生下列影响:
- 在一般情况中(没有指定O_NOBLCOK),只读 open 要阻塞到某个其他进程为写而打开此 DIDO。类似地,只写 open 要阻塞到某个其他进程为读而打开它。
- 如果指定了 O_NOBLOCK,则只读 open 立即返回。但是,如果没有进程已近为读而打开一个 FIFO,那么只写 open 将出错返回 -1,其 errno 为 ENXIO。
类似于管道,若用 write 写一个尚无进程为读而打开的 FIFO,则产生 SIGPIPE。若某个 FIFO 的最后一个写进程关闭了 FIFO,则将为该 FIFO 的读进程产生一个文件结束标志。
一个给定的 FIFO 有多个写进程是很常见的。这就意味着如果不希望多个进程写的数据互相穿插,则需要考虑原子写操作。正如对于管道一样,常量 PIPE_BUF 说明了可被原子的写到 FIFO 的最大数据量。
FIFO 有两种用途
- FIFO 由 shell 命令使用以便将数据从一条管道线传送到另一条,为此无需创建中间零时文件。
- FIFO 用于客户进程-服务器进程应用程序中,以在客户进程和服务器进程之间传送数据。
这种安排可以工作,但也有不足之处。其中之一是服务器进程不能判断一个客户进程是否崩溃终止,这就使得客户专用 FIFO 会遗留在文件系统中。另外一个不足之处是服务器必须捕捉 SIGPIPE 信号,因为客户进程在发一个请求后没有响应就可能终止,于是留下一个只有写进程(服务器进程)而没有读进程的客户专用 FIFO。
如果服务器进程以只读方式打开众所周知的 FIFO(因为服务器只需要读),则每客户当进程数量从 1 减到 0时,服务器进程就将在管道中读到一个文件结束标记。为使服务器避免处理这种情况,一种常用的技巧是使服务器进程以读写方式打开其 FIFO。
为什么管道文件间没有消失,还说管道生命周期随进程
生命周期也随进程,不冲突,虽然磁盘上能看到,但核心内容即分配的内存已经释放,下一次打开会分配新的内存。
文件虽然存在,但操作系统为其分配的内存已经没了(管道里的数据被操作系统回收了)。
与匿名管道的对比:
- 创建方式不同
- 适用范围不同
具体使用案例
因为命名管道适用于两个没有血缘关系的进程通信,所以可以实现 server 进程向 client 进程发数据,而 client 进程回显 server 发过来的数据。
代码实现
- [进程通信] 进程间通信 之 管道
- 进程间通信之管道
- 进程间通信之 管道
- 进程间通信 之 管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之 管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之--- 管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之管道
- 进程间通信之管道通信
- 线程无法停止的一种情况
- 用thinkPHP创建在index下的控制器
- bzoj1059: [ZJOI2007]矩阵游戏
- 巫师算星座
- C++的输入优化
- 进程间通信之管道
- 配置mysql的主从复制
- Win10下的Java下载安装与环境配置
- 哈尔滨理工大学第七届程序设计竞赛决赛 D 数圈圈
- 【模板】可持久化线段树(主席树)
- 手记_轻松掌握MySQL数据库存储过程_咕泡
- 基本数据类型和引用数据类型的区别
- linux常用命令
- Java类加载器总结