linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。而对Unix发展做出重大贡献的两大主力AT&T(原为American Telephone & Telegraph的缩写,也是中文译名美国电话电报公司由来)的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同。前者对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,通信进程局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。Linux则把两者继承了下来。
最初Unix IPC包括:管道、FIFO、信号。
System V IPC包括:System V消息队列、System V信号灯、System V共享内存区。
Posix IPC包括: Posix消息队列、Posix信号灯、Posix共享内存区。
有两点需要简单说明一下:1)由于Unix版本的多样性,电子电气工程协会(IEEE)开发了一个独立的Unix标准,这个新的ANSI Unix标准被称为计算机环境的可移植性操作系统界面(Portable Operating System Interface,PSOIX)。现有大部分Unix和流行版本都是遵循POSIX标准的,而Linux从一开始就遵循POSIX标准;2)BSD并不是没有涉足单机内的进程间通信(socket本身就可以用于单机内的进程间通信)。事实上,很多Unix版本的单机IPC留有BSD的痕迹,如4.4BSD支持的匿名内存映射、4.3+BSD对可靠信号语义的实现等等。
linux 所支持的各种IPC手段,在本文接下来的讨论中,为了避免概念上的混淆,在尽可能少提及Unix的各个版本的情况下,所有问题的讨论最终都会归结到Linux环境下的进程间通信上来。并且,对于Linux所支持通信手段的不同实现版本(如对于共享内存来说,有Posix共享内存区以及System V共享内存区两个实现版本),将主要介绍Posix API。
匿名管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
两者的不同点:
(1)匿名管道它没有名字,只能用于具有亲缘关系进程间的通信。有名管道FIFO克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
(2)匿名管道对于管道两端的进程而言是一个文件,但不是Linux某种类型的文件、不属于某个文件系统,而且仅存在于内存中;pipe()函数打开了两个文件描述符,分别用于读写。有名管道提供一个路径名与之关联,是linux文件类型的一种,因FIFO文件形式存在于文件系统中。
相同点:
(1)管道和FIFO的数据是字节流,应用程序之间必须事先确定特定的传输"协议",采用传播具有特定意义的消息。
(2)单向(半双工)数据流。
(3)系统对管道和FIFO的两个限制OPEN_MAX(一个进程任意时刻打开的最大描述符数)、PIPI_BUF(可原子地写往一个管道或FIFO的最大数据量,posix要求至少512)。
4)都是随进程持续的IPC(IPC对象一直存在到打开该对象的最后一个进程关闭该对象为止。)
管道常用于两个方面:
(1)在shell中时常会用到管道(作为输入输入的重定向),在这种应用方式下,管道的创建对于用户来说是透明的;
(2)用于具有亲缘关系的进程间通信,用户自己创建管道,并完成读写操作。
参考文章:UNIX域协议
Unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所使用的API就是在不同主机上执行客户/服务器通信所用的API(套接字API)。
Unix域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。Unix域套接字提供流和数据报两种接口。Unix域数据报服务是可靠的,既不会丢失消息也不会传递出错。它是套接字和管道之间的混合物。
使用Unix域套接字的理由:
(1)Unix域套接字往往比通信两端位于同一主机的TCP套接字快一倍(TCPv3)。Unix域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。
(2)可用于在同一台主机的不同进程之间传递描述符。
(3)Unix域套接字较新的实现把客户的凭证(用户ID和组ID)提供给服务器,从而提供了额外的安全检查措施。
为了创建一对非命名的、相互连接的UNIX域套接字,用户可以使用它们面向网络的域套接字接口,也可以使用socketpair函数。
信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数signal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。sigaction包含了信号产生的相关信息。
消息队列是消息的链接表,包括Posix消息队列和system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。而且消息队列是随内核持续的(IPC对象会一直存在,直到内核重启或显示删除该对象为止)。
参考文章:进程通信方式:共享内存区
mmap:Linux环境进程间通信(五): 共享内存(上)
使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如与信号量结合使用,来达到进程间的同步及互斥。
主要作为进程间以及同一进程不同线程之间的同步手段。
各种同步方式:
线程同步的几种方式:参考文章:进程同步和线程同步
更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
匿名管道和命名管道:Linux环境进程间通信(一)
信号:Linux环境进程间通信(二): 信号(上) Linux环境进程间通信(二): 信号(下)
消息队列:Linux环境进程间通信(三)
信号量:Linux环境进程间通信(四)
共享内存:Linux环境进程间通信(五): 共享内存(上) Linux环境进程间通信(五): 共享内存(下)
套接字:Linux 环境进程间通信(六)