参考:
Linux进程间通信总结-百度开发者中心
Linux操作系统提供了多种进程间通信(IPC)的方式,每种方式都有其独特的应用场景和优缺点。下面将对Linux下的进程间通信方式进行总结和比较。
管道(Pipe)
管道是最早的进程间通信方式之一,它通过将一个进程的输出连接到另一个进程的输入来实现通信。管道可以分为匿名管道和有名管道两种。匿名管道只能在具有亲缘关系的进程之间使用,有名管道则可以在任意两个进程之间使用。
优点:
- 实现简单:管道是Linux操作系统自带的一种通信方式,使用起来比较简单。
- 无须第三方支持:管道不需要第三方软件的支撑,因此性能较高。
缺点:
- 通信能力有限:管道只能单向传输数据,且数据量较小,不适合传输大量数据。
- 通信双方必须事先存在:管道只能在具有亲缘关系的进程之间使用,且通信双方必须事先存在。
消息队列(Message Queue)
消息队列是一种基于消息的通信方式,它允许进程之间发送和接收消息。消息队列可以实现异步通信,即发送和接收消息的进程可以不同时运行。
优点:
- 支持异步通信:消息队列可以实现异步通信,提高系统的并发性能。
- 数据持久化:消息队列可以将数据持久化存储,保证数据的安全性。
缺点:
- 性能开销较大:消息队列需要维护消息的存储和转发,因此性能开销较大。
- 可能会引起死锁:在多进程访问同一个消息队列时,可能会引起死锁问题。
- 缺点:如果a给b发送的数据过大,并且通信频繁,那消息队列就不合适了,因为数据过大,a发送数据的时间长,b去拷贝数据花费时间也长,效率就会变低。
- 优点:管道一旦相关进程退出,那里面的数据也就没有了,但消息队列不一样,一个进程向里面写入数据后退出,另一个进程仍然可以取数据。
参考:https://www.cnblogs.com/feily/articles/14160817.html
消息队列不适合比较大数据的传输
,因为在内核中每个消息体都有一个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。在 Linux 内核中,会有两个宏定义 MSGMAX 和 MSGMNB,它们以字节为单位,分别定义了一条消息的最大长度和一个队列的最大长度。消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。
共享内存(Shared Memory)
共享内存允许多个进程共享一段内存空间,从而实现快速的数据交换。共享内存可以是全共享内存或段共享内存,其中全共享内存允许多个进程同时读写同一段内存空间,而段共享内存则只允许一个进程读写某一段内存空间。
优点:
- 速度快:共享内存允许多个进程直接访问同一段内存空间,因此速度非常快。
- 数据共享:共享内存可以实现多个进程之间的数据共享。
缺点:
- 同步问题:多个进程同时访问共享内存时,需要解决同步问题,以避免出现竞态条件。
- 可能导致死锁:在多进程访问共享内存时,可能会引起死锁问题。
针对消息队列的缺点,共享内存允许多个进程共享一个给定的存储区,由于他们是共享一块内存数据,减少了内存拷贝的时间,因此速度非常快。
但这里我们可能会问:每个进程不是独立的吗?怎么可以共享内存呢?
其实,系统加载一个进程时,分配给进程的内存并不是实际的物理内存,而是虚拟内存空间,我们可以让两个进程各自拿出一块虚拟地址空间来,然后映射到相同的物理内存中,这样虽然两个进程有独立的虚拟地址空间,但有一部分是映射的相同的物理内存,这样就完成了内存共享机制,如下图所示:
缺点:多进程竞争内存,类似于我们平常说的线程安全。
信号量(Semaphore)
信号量是一种用于控制多个进程对共享资源的访问的机制。它通过维护一个计数器来记录可用资源的数量,当一个进程需要访问资源时,需要先获取信号量。如果信号量的值为0,则表示资源不可用;如果信号量的值大于0,则表示资源可用,该进程可以获取资源并减少信号量的值。
优点:
- 可以控制并发访问:信号量可以控制多个进程对共享资源的并发访问,避免出现竞态条件。
- 实现简单:信号量的实现比较简单,使用起来也比较方便。
缺点:
- 可能会导致死锁:在多进程访问共享资源时,如果不合理地使用信号量,可能会导致死锁问题。
- 无法传递大量数据:信号量只能用于控制资源的访问,无法传递大量数据。
套接字(Socket)
前面提到的管道、消息队列、共享内存以及信号量都是在同一台主机上进行进程间通信,那要想跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。
实际上,Socket 通信不仅可以跨网络与不同主机的进程间通信,还可以在同主机上进程间通信。
套接字基于网络协议进行数据传输,可以用于不同操作系统之间的通信。套接字可以分为流套接字和数据报套接字两种类型。流套接字提供可靠的、双向的、面向连接的数据传输服务;数据报套接字提供不可靠的、无连接的数据传输服务。
优点:
- 支持跨平台通信:套接字适用于不同主机之间的进程间通信,可以实现跨平台通信。
- 其实也可以用于同一个主机上不同进程间的数据通信,也就是unix域Socket。
参考:https://www.cnblogs.com/feily/articles/14160817.html
根据创建 socket 类型的不同,通信的方式也就不同:
- 实现 TCP 字节流通信:socket 类型是 AF_INET 和 SOCK_STREAM;
- 实现 UDP 数据报通信:socket 类型是 AF_INET 和 SOCK_DGRAM;
- 实现本地进程间通信:「本地字节流 socket 」类型是 AF_LOCAL 和 SOCK_STREAM,「本地数据报 socket 」类型是 AF_LOCAL 和 SOCK_DGRAM。另外,AF_UNIX 和 AF_LOCAL 是等价的,所以 AF_UNIX 也属于本地 socket;
更多待补充。