Linux进程间通信IPC的几种方式简介

Linux进程通信的源头

      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下进程间通信的几种主要手段


1)管道(Pipe)及有名管道(named pipe,FIFO)  

匿名管道是Linux支持的最初Unix IPC形式之一,具有以下特点:

  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;STREAMS管道是一个双向(全双工)管道,单个STREAMS管道就能向父、子进程提供双向数据流。Solaris支持STREAMS管道,Linux的可选附加包也提供了STREAMS管道。
  • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
  • 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

两者的不同点:

(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)用于具有亲缘关系的进程间通信,用户自己创建管道,并完成读写操作。


2)Unix域协议

参考文章:UNIX域协议

       Unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所使用的API就是在不同主机上执行客户/服务器通信所用的API(套接字API)。

    Unix域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。Unix域套接字提供流和数据报两种接口。Unix域数据报服务是可靠的,既不会丢失消息也不会传递出错。它是套接字和管道之间的混合物


使用Unix域套接字的理由

(1)Unix域套接字往往比通信两端位于同一主机的TCP套接字快一倍(TCPv3)。Unix域套接字仅仅复制数据,并不执行协议处理,不需要添加或删除网络报头,无需计算校验和,不要产生顺序号,无需发送确认报文。

(2)可用于在同一台主机的不同进程之间传递描述符。

(3)Unix域套接字较新的实现把客户的凭证(用户ID和组ID)提供给服务器,从而提供了额外的安全检查措施。


为了创建一对非命名的、相互连接的UNIX域套接字,用户可以使用它们面向网络的域套接字接口,也可以使用socketpair函数。


3)信号(Signal)

     信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数signal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。sigaction包含了信号产生的相关信息。

4)消息队列

   消息队列是消息的链接表,包括Posix消息队列和system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。而且消息队列是随内核持续的(IPC对象会一直存在,直到内核重启或显示删除该对象为止)。

5)共享内存

参考文章:进程通信方式:共享内存区          

        mmap:Linux环境进程间通信(五): 共享内存(上)

        System V共享内存: Linux环境进程间通信(五): 共享内存(下)

    使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如与信号量结合使用,来达到进程间的同步及互斥

6)信号量(semaphore)

   主要作为进程间以及同一进程不同线程之间的同步手段。


各种同步方式

线程同步的几种方式:参考文章:进程同步和线程同步


7)套接口(Socket)

    更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。


参考资料:

匿名管道和命名管道:Linux环境进程间通信(一)

信号:Linux环境进程间通信(二): 信号(上) Linux环境进程间通信(二): 信号(下)

消息队列:Linux环境进程间通信(三)

信号量:Linux环境进程间通信(四)

共享内存:Linux环境进程间通信(五): 共享内存(上) Linux环境进程间通信(五): 共享内存(下)

套接字:Linux 环境进程间通信(六)

你可能感兴趣的:(Linux,linux细枝末节)