Unix/Linux提供了大量的IPC:管道,套接字,共享内存,dbus,消息队列......
每种应用最合适的应用是什么?它们的表现如何?
这是七大:
管
仅在与父/子相关的过程中有用.打电话pipe(2)
和fork(2)
.单向.
FIFO或命名管道
与普通管道不同,两个不相关的进程可以使用FIFO.打电话mkfifo(3)
.单向.
套接字和Unix域套接字
双向的.适用于网络通信,但也可以在本地使用.可用于不同的协议.TCP没有消息边界.打电话socket(2)
.
消息队列
OS维护离散消息.见SYS/msg.h.
信号
Signal将整数发送到另一个进程.与多线程不能很好地融合.打电话kill(2)
.
信号
多进程或线程的同步机制,类似于等待浴室的人员队列.见SYS/sem.h中.
共享内存
做你自己的并发控制.打电话shmget(2)
.
选择一种方法而不是另一种方法的一个决定因素是消息边界问题.您可能希望"消息"彼此离散,但它不适用于像TCP或管道这样的字节流.
考虑一对echo客户端和服务器.客户端发送字符串,服务器接收它并将其发回.假设客户端发送"Hello","Hello"和"How a a answer?".
使用字节流协议,服务器可以接收"地狱","oHelloHow"和"关于答案?"; 或者更现实地说"HelloHelloHow关于答案?".服务器不知道消息边界的位置.
一个古老的技巧是将消息长度限制为CHAR_MAX
或UINT_MAX
同意首先在char
或中发送消息长度uint
.因此,如果您在接收方,则必须首先阅读消息长度.这也意味着一次只有一个线程应该读取消息.
使用UDP或消息队列等离散协议,您不必担心此问题,但编程上的字节流更容易处理,因为它们的行为类似于文件和stdin/out.
共享内存可能是最有效的,因为您可以在其上构建自己的通信方案,但它需要大量的关注和同步.解决方案也可用于将共享内存分发到其他计算机.
套接字是目前最便携的,但需要比管道更多的开销.透明地在本地或通过网络使用套接字的能力是一个很大的好处.
消息队列和信号对于硬实时应用程序非常有用,但它们并不灵活.
这些方法自然地为进程之间的通信创建,并且在进程中使用多个线程会使事情复杂化 - 特别是对于信号.
这是一个简单基准的网页:https://sites.google.com/site/rikkus/sysv-ipc-vs-unix-pipes-vs-unix-sockets
据我所知,每个人都有自己的优势:
管道I/O是最快的,但需要父/子关系才能工作.
Sysv IPC具有已定义的消息边界,可以在本地连接不同的进程.
UNIX套接字可以在本地连接不同的进程,并且具有更高的带宽但没有固有的消息边界.
TCP/IP套接字甚至可以通过网络连接任何进程,但具有更高的开销和没有固有的消息边界.
值得注意的是,许多库在另一个库之上实现了一种类型的东西.
共享内存不需要使用可怕的sysv共享内存函数 - 使用mmap()更加优雅(mmap如果你想要它命名为tmpfs/dev/shm中的文件;如果你想要mmap/dev/zero分叉而不是exec'd进程匿名继承它).话虽如此,它仍然会使您的进程需要同步以避免出现问题 - 通常通过使用其他一些IPC机制来同步访问共享内存区域.