一、管道
它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。

应用场景:
只能用于具有亲缘关系的进行通信,使用面相对较窄,实际开发中较少使用;

二、FIFO
FIFO,也称为命名管道,它是一种文件类型。
FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。

应用场景:
可以用于任意进程间的通信,对于大块数据的传输效率较高,可应用于单进程大量数据传递,和多个进程向一个进程传递数据;

三、消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

优点:
 A. 我们可以通过发送消息来几乎完全避免命名管道的同步和阻塞问题。
 B. 我们可以用一些方法来提前查看紧急消息。
缺点:
 A. 与管道一样,每个数据块有一个最大长度的限制。
 B. 系统中所有队列所包含的全部数据块的总长度也有一个上限。 
使用场景:
进程间传递简单的命令和控制消息,如配置更新通知,多进程对多进程的通信等,可以简化代码逻辑;--建议使用全双工管道替代;

四、信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。

使用场景:
互斥 类似于mutex,但是mutex只能是加锁的人解锁   
同步 -> 线程1和线程2 -> 线程3 
某种资源数为N,多个进程都在使用该资源,为了进行进程间的互斥,可以使用初始值为N的信号量;--建议使用记录锁替代;

五、共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
消息队列和管道基本上都是4次拷贝,而共享内存(mmap, shmget)只有两次。
第一步读磁盘文件是要经过一次系统调用的,它首先将文件内容从磁盘拷贝到内核空间的一个缓冲区,然后再将这些数据拷贝到用户空间,实际上是两次数据拷贝。第三步回写也一样也要经过两次数据拷贝。
4次:1,write()输入从磁盘到A内核空间。2,写进B用户空间。3,B调用read()读入内核空间。4,从内核空间中放入磁盘.
而内存映射文件是操作系统的提供的一种机制,可以减少这种不必要的数据拷贝,从而提高效率。它由mmap()将文件直接映射到用户空间,mmap()并没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行了一次数据拷贝 ,比read进行两次数据拷贝要好上一倍,因此,内存映射的效率要比read/write效率高。
2次:1,输入到用户空间。 2,用户空间到输出。
零拷贝?

使用场景:
传递很大的数据
大量读同一数据的场景 
最为高效的进程间通信方式,进程可以直接读写内存,不需要任何数据拷贝,适用于多个进程共享数据,或进程间频繁的进行大量的数据交互;--建议使用mmap方式;

六、信号

使用场景:
接收进程某个时间已经发生,死亡。 
无法传递数据,而且信号的种类有限,只适用于完成一些简单的事件通知任务,如配置跟新信号通知,一个服务通过信号告知另一个服务自身状态;

七、套接字

使用场景:
如果系统需要支持分布式部署,服务可能在同一设备或者不同设备,此时使用网络套接字比较合适,提高了扩展性;

八、unix域套接字

使用场景:
某个服务与多个服务同时通信,此时需要维护多个通信通道,使用unix套接字,可以使用linux IO多路复用功能;--建议优先考虑网络套接字;

linux系统下进程通信方式包括:信号量、管道(包括匿名管道和命名管道)、消息队列、共享内存、套接字(socket)。前面四种方式用于本地进程间通信,属于同一台计算机内通信;socket一般默认指的是TCP/IP socket,用于跨不同计算机之间进行网络通信。实质上,socket同样可用于本地进程间通信,而且与其他IPC方式相比,具有更高效率和更加灵活性。用于本地进程间通信的socket称为unix域套接字(unix domain socket)。
与传统基于TCP/IP协议栈的socket不同,unix domain socket以文件系统作为地址空间,不需经过TCP/IP的头部封装、报文ack确认、路由选择、数据校验与重传过程,因此传输速率上也不会受网卡带宽的限制。unix domain socket数据传输时,以系统文件系统的权限机制访问,内核根据socket路径名称直接将数据拷贝到接收方socket的缓冲区,数据传输效率上要远高于TCP/IP的socket。从数据传输模型和传输过程看,unix domain socket与管道类似,因为管道的发送与接收数据同样依赖于路径名称。


仇实
23 声望0 粉丝

头像为AI合成