首先先介绍一下进程间通信的概念以及进程间通信的目的
进程间通信概念:
进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。另外,系统空间是“公共场所”,各进程均可以访问,所以内核也可以提供这样的条件。此外,还有双方都可以访问的外设。在这个意义上,两个进程当然也可以通过磁盘上的普通文件交换信息,或者通过“注册表”或其它数据库中的某些表项和记录交换信息。广义上这也是进程间通信的手段,但是一般都不把这算作“进程间通信”。
进程间通信的目的:
一 资源共享,多个进程之间共享同样的资源
二 数据传输,一个进程需要将它的数据发送给另一个进程
三 通知事件, 一个进程需要向另一个或者另一组发送消息,通知发生了什么事件(子进程终止时要通知父进程)
四 进程控制, 有些进程需要控制其他进程(Debug进程),此时拦截进程希望能够拦截另一个进程的所有陷和异常,并能够及时知道它的状态改变。
**
通信方式之一 ———- 管道
**
管道:管道是UNIX系统最古老的通信方式,我们把一个进程连接到另一个进程的数据流称为管道。
本质:
管道的本质是内核提供的一段内存
分类
管道分为匿名管道和命名管道
匿名管道
特性:
① 只适用于有亲缘关系的进程(父子之类的),拥有相同的文件描述符
② 半双工通信,如果想全双工通信,就要创建两个管道,一个读,一个写
③ 面向字节流
④ 内置了同步与互斥
⑤ 生命周期随进程
创建:
创建一个匿名管道
函数原型
#include<unistd.h>
int pipe(int fd[2]);
int pipe2(int fd[2],int flags);
返回值
成功返回 0
失败返回 -1
参数
fd 是一个输出型参数,数组内容是文件描述符,
fd[0] 表示读端
fd[1] 表示写端
flags 是创建管道的方式 阻塞的方式 非阻塞的方式
销毁:
所有打开这个匿名管道进程都销毁的时候,管道销毁,也就是说匿名管道的生命周期随进程。
匿名管道的读写规则
如果关闭所有读,对管道进行write操作,系统会发送SIGPIPE信号,终止进程。
如果关闭写,对管道read操作,那么read返回0
阻塞的方式:
①对空管道进行读,阻塞在read()函数中,等管道中有数据,读出数据
②对满管道进行写,阻塞在write()函数中,等管道中有剩余地方,写入数据
非阻塞的方式
①对空管道进行读,read()直接返回错误,不阻塞
②对满管道进行写,write()函数直接返回错误
命名管道
是一种特殊类型的文件
特性:
① 适用于任意进程
② 半双工通信,如果想全双工通信,就要创建两个管道,一个读,一个写
③ 面向字节流
④ 内置了同步与互斥
⑤ 生命周期随进程
创建:
创建一个命名管道
有两种创建方式,
一种是通过命令行的方式创建
mkfifo filename
一种是通过程序创建
int mkfifo(const char* pathname,mode_t mode);
返回值
成功返回 0
失败返回 -1
参数
pathname 是文件的路径名
mode 是创建的特殊文件的权限
销毁:
所有打开这个匿名管道进程都销毁的时候,管道销毁,也就是说匿名管道的生命周期随进程。或者这个命名管道文件被销毁。
命名管道的读写规则
阻塞的方式open:
①当使用“只读”的方式open一个命名管道,会被阻塞在open中,直到一个进程使用“写的方式”打开了这个命名管道
②当使用“只写”的方式open一个命名管道,会阻塞在open函数中,直到一个进程用“读的方式”open了命名管道
非阻塞的方式open
①当使用“只读”的方式open一个命名管道,使用read函数读的时候,read会直接返回0。如果有进程使用“写”的方式打开了命名管道,但是却没有“写”数据进去管道,那么read函数返回-1。
②如果没有进程使用“读”的方式open命名管道,使用“写”的方式open命名管道会直接返回失败,并且报错,错误码为ENXIO
匿名管道和命名管道的区别
①匿名管道由pipe()函数创建并打开。
②命名管道由mkfifo()函数创建,由open函数打开。
③命名管道(FIFO)和匿名管道(pipe)他们创建和打开的方式不同。
④匿名管道只适用于有亲缘关系的进程,命名管道适用于任意进程。