管道:
本质:内核的缓存
管道分类:
管道是进程间通信中最古老的方式,它是指用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件。我们将一个进程到另一个进程的数据流,称之为“管道” 。
它包括匿名管道和命名管道两种。
匿名管道:
#include<unistd.h>
功能:创建一个无名管道
原型:
int pipe (int fd[2]);
参数:
fd:文件描述符数组,其中fd[0]表示读端,fd[1]表示写端。
返回值:
成功返回0 ;失败返回错误代码。
特点:
1.只用于有亲缘关系的进程之间的通信,通常用于父子进程间的通信。
2.必须同时读写
3.管道提供流式服务
4.一般而言,进程退出,管道释放,所以管道的生命周期随进程
5.一般来说,内核会对管道操作进行同步和互斥
6.管道是半双工的,数据只能单向流动,需要双方通信时,需要建立两个管道
示例:从键盘读到数据,写入管道,读取管道,显示到屏幕。
代码实现:
运行结果:
用fork来共享管道原理
代码实现:
运行结果:
示例:实现带管道的命令“ls -l | wc -l”
代码实现:
运行结果:
匿名管道读写规则:
当没有数据可读时
- read调用阻塞,即进程暂停执行,一直等到与数据来到为止
- read调用返回-1,errno值为EAGAIN
当管道满的时候
- write调用阻塞,知道有进程来读数据为止
- 调用返回-1,errno值为EAGAIN
如果所有管道写端对应的文件描述符被关闭,则read返回0
如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号
SIGPIPE,进而可能导致write进程退出当要写入的数据量不大于SIG_BUF时,linux保证写入的原子性
当要写入的数据量大于SIG_BUF时,linux不再保证写入的原子性
命名管道:
实现无亲缘关系进程之间的通信,用于运行于同一台机器上的任意两个进程间的通信。
如果我们想在两个不相关的进程之间交换数据,使用FIFO文件来做这项工作,它就叫做命名管道。
命名管道是一种特殊的文件。
#include <unistd.h>
功能:创建一个命名管道
原型:
int mkfifo(const char* filename ,mode_t mode )
返回值:
0表示创建成功
-1表示创建失败(例如:创建的目录没有权限)
匿名管道和命名管道的区别:
1.匿名管道是由pipe函数创建并打开
2.命名管道由mkfifo函数创建,打开用open
3.FIFO(命名管道)和pipe(匿名管道)之间唯一的区别就是他们的创建方式和打开方式不同,但一旦这些动作完成之后,他们具有相同的语义
命名管道读写规则:
如果当前打开操作是为读打开FIFO时
- 阻塞直至有进程为写而打开该FIFO
- 立刻返回成功
如果当前打开操作是为写打开FIFO时
- 阻塞直至有进程为读而打开该FIFO
- 立刻返回失败,错误码为ENXIO