Linux使用的进程间通信方式主要有6种:
(1)管道(pipe)和有名管道(FIFO)
(2)信号(signal)
(3)消息队列(报文队列)
(4)共享内存
(5)信号量
(6)套接字(socket)
一. 管道
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
· 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
· 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
· 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
· 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。FIFO不同于管道之处在于,它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间)。
值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
二. 信号
信号是在软件层次上对中断机制的一种模拟,所以也称为软中断,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达。信号是进程间通信机制中唯一的异步通信机制。
信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源,最常用发送信号的系统函数是kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort()。linux主要有两个函数实现信号的安装,即设置信号关联动作:signal()、sigaction()。
三. 消息队列
消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。
系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。
消息队列就是一个消息的链表。每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。
对消息队列的操作无非有下面三种类型:打开或创建消息队列 ,读写操作,获得或设置消息队列属性。
四. 共享内存
共享内存可以说是最有用的进程间通信方式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。在内核中,共享内存机制有四种操作,即四个库函数: shmget(),shmat(),shmdt()和shmctl()
五. 信号量
共享内存为进程间通讯提供了一种效率很高的手段,但是这种机制所提供的只是狭义的通信手段,而并不提供进程间同步的功能。所以,共享内存作为广义的进程间通信手段需要有其他机制配合。同时,除共享内存外,还有其他需要共享资源的场合也需要进程间同步的手段。所以,原则上讲,只要两个进程直接共享某个资源,就得要同步的手段。信号量就是Linux中进程间同步手段。
与信号量有关的操作有三种:
semget():创建或寻找信号量
semop():信号量操作, 操作一个或一组信号
信号量的值与相应资源的使用情况有关,
当它的值大于 0 时,表示当前可用的资源数的数量;
当它的值小于 0 时,其绝对值表示等待使用该资源的进程个数。
信号量的值仅能由 PV 操作来改变。
semop的第二个参数是信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作, 一个是+1,即V(发送信号)操作。
semctl():信号量的控制与管理
六. Socket通信
以上通信方式的应用局限在单一计算机内的进程间通信;基于BSD套接口(Socket)不仅可以实现单机内的进程间通信,还可以实现不同计算机进程之间的通信。一个socket在逻辑上有三个特征:网域,类型和规程,即创建socket的函数的三个参数:int socket(int domain, int type, int protocol);
网域表明这个socket用于哪个网络,AF_INET表示因特网,AF_UNIX是本地socket通信所用的。类型表明在网络中通信所遵循的模式,主要有两种:面向连接和无连接,即SOCK_STREAM和SOCK_DGRAM两种。面向连接的报文传递是同步的,如tcp,无连接的是异步的,如udp。最后是规程,一般来说,网域和类型结合一起大致就确定了适用的规程。例如,网域是AF_INET,类型是无连接的,则规程基本上就是UDP了,一般默认填0。
参考资料:
《Linux内核情景分析》
http://www.cnblogs.com/linshui91/archive/2010/09/29/1838770.html
http://blog.csdn.net/liuzhanchen1987/article/details/7455208