所谓进程间通信指的是系统中两个进程之间的通信,不同的进程都在各自的地址空间中、相互独立、隔离,所以它们是处在于不同的地址空间中,因此相互通信比较难,Linux 内核提供了多种进程间通信的机制。
大部分的程序是不要考虑进程间通信的,因为大家所接触绝大部分程序都是单进程程序(可以有多个线程),对于一些复杂、大型的应用程序,则会根据实际需要将其设计成多进程程序,譬如 GUI 、服务区应用程序等。在一些中小型应用程序中通常不会将应用程序设计成多进程程序,自然而然便不需要考虑进程间通信的问题
进程间通信的机制有哪些?
总结如下:
⚫ UNIX IPC :管道、 FIFO 、信号;
⚫ System V IPC :信号量、消息队列、共享内存;
⚫ POSIX IPC :信号量、消息队列、共享内存;
⚫ Socket IPC :基于 Socket 进程间通信。
1、管道和FIFO
管道是 UNIX 系统上最古老的 IPC 方法,它在 20 世纪 70 年代早期 UNIX 的第三个版本上就出现了。 把一个进程连接到另一个进程的数据流称为管道,管道被抽象成一个文件,也就是管道文件( pipe ) 这样一种文件类型。
管道包括三种:
⚫ 普通管道 pipe :通常有两种限制,一是单工,数据只能单向传输;二是只能在父子或者兄弟进程间使用;
⚫ 流管道 s_pipe :去除了普通管道的第一种限制,为半双工,可以双向传输;只能在父子或兄弟进程间使用;
⚫ 有名管道 name_pipe ( FIFO ):去除了普通管道的第二种限制,并且允许在不相关(不是父子或兄弟关系)的进程间进行通讯。
普通管道可用于具有亲缘关系的进程间通信,并且数据只能单向传输,如果要实现双向传输,则必须要使用两个管道;而流管道去除了普通管道的第一种限制,可以半双工的方式实现双向传输,但也只能在具有亲缘关系的进程间通信;而有名管道(FIFO )则同时突破了普通管道的两种限制,即可实现双向传输、又能 在非亲缘关系的进程间通信。
2、信号
用于通知接收信号的进程有某种事件发生,所以可用于进程间通信;除了用于进程间通信之外,进程还可以发送信号给进程本身。
3、消息队列
消息队列是消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺陷。消息队列包括 POSIX 消息队列和 System V 消息队列。
消息队列是 UNIX 下不同进程之间实现共享资源的一种机制, UNIX 允许不同进程将格式化的数据流以消息队列形式发送给任意进程,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。
4、信号量
信号量是一个计数器,与其它进程间通信方式不大相同,它主要用于控制多个进程间或一个进程内的多个线程间对共享资源的访问,相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志,除了用于共享资源的访问控制外,还可用于进程同步。
它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源,因此,主要作为进程间以及同一个进程内不同线程之间的同步手段。Linux 提供了一组精心设计的信号量接口来对信号量进行操作,它们声明在头文件 sys/sem.h 中。
5、共享内存
共享内存就是映射一段能被其它进程所访问的内存,这段共享内存由一个进程创建,但其它的多个进程 都可以访问,使得多个进程可以访问同一块内存空间。共享内存是最快的 IPC 方式,它是针对其它进程间通信方式运行效率低而专门设计的,它往往与其它通信机制,譬如结合信号量来使用,以实现进程间的同步和通信。
6、套接字(Socket)
Socket 是一种 IPC 方法,是基于网络的 IPC 方法,允许位于同一主机(计算机)或使用网络连接起来的不同主机上的应用程序之间交换数据,说白了就是网络通信。
在一个典型的客户端 / 服务器场景中,应用程序使用 socket 进行通信的方式如下:
⚫ 各个应用程序创建一个 socket 。 socket 是一个允许通信的“设备”,两个应用程序都需要用到它。
⚫ 服务器将自己的 socket 绑定到一个众所周知的地址(名称)上使得客户端能够定位到它的位置