比较 Unix/Linux IPC
Unix/Linux 提供了许多 IPC:管道、套接字、共享内存、dbus、消息队列...
每种最适合的应用程序是什么,它们的性能如何?
Lots of IPCs are offered by Unix/Linux: pipes, sockets, shared memory, dbus, message-queues...
What are the most suitable applications for each, and how do they perform?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Unix IPC
以下是七大:
管道
仅在作为父/子相关的进程中有用。 调用
pipe(2)
和fork(2)
。 单向。FIFO,或命名管道
与普通管道不同,两个不相关的进程可以使用 FIFO。 调用
mkfifo(3)
。 单向。套接字 和 Unix 域套接字
双向。 用于网络通信,但也可以在本地使用。 可用于不同的协议。 TCP 没有消息边界。 调用
socket(2)
。消息队列
操作系统维护离散消息。 请参阅 sys/msg.h。
信号
信号将一个整数发送到另一个进程。 与多线程不能很好地配合。 调用
kill(2)
。信号量
多进程或多线程的同步机制,类似于人们等待上厕所的队列。 请参阅 sys/sem.h。
共享内存
进行自己的并发控制。 调用
shmget(2)
。消息边界问题
选择一种方法而不是另一种方法时的一个决定因素是消息边界问题。 您可能期望“消息”彼此离散,但这不适用于 TCP 或 Pipe 等字节流。
考虑一对 echo 客户端和服务器。 客户端发送字符串,服务器接收它并立即发回。 假设客户端发送“你好”、“你好”和“回答怎么样?”。
使用字节流协议,服务器可以接收“Hell”、“oHelloHow”和“about an answer?”; 或者更现实地说“你好你好,答案怎么样?”。 服务器不知道消息边界在哪里。
一个古老的技巧是将消息长度限制为
CHAR_MAX
或UINT_MAX
并同意首先以char
或uint 形式发送消息长度
。 所以,如果你在接收端,你必须先读取消息长度。 这也意味着一次只能有一个线程执行消息读取。使用 UDP 或消息队列等离散协议,您不必担心这个问题,但以编程方式处理字节流更容易处理,因为它们的行为类似于文件和标准输入/输出。
Unix IPC
Here are the big seven:
Pipe
Useful only among processes related as parent/child. Call
pipe(2)
andfork(2)
. Unidirectional.FIFO, or named pipe
Two unrelated processes can use FIFO unlike plain pipe. Call
mkfifo(3)
. Unidirectional.Socket and Unix Domain Socket
Bidirectional. Meant for network communication, but can be used locally too. Can be used for different protocol. There's no message boundary for TCP. Call
socket(2)
.Message Queue
OS maintains discrete message. See sys/msg.h.
Signal
Signal sends an integer to another process. Doesn't mesh well with multi-threads. Call
kill(2)
.Semaphore
A synchronization mechanism for multi processes or threads, similar to a queue of people waiting for bathroom. See sys/sem.h.
Shared memory
Do your own concurrency control. Call
shmget(2)
.Message Boundary issue
One determining factor when choosing one method over the other is the message boundary issue. You may expect "messages" to be discrete from each other, but it's not for byte streams like TCP or Pipe.
Consider a pair of echo client and server. The client sends string, the server receives it and sends it right back. Suppose the client sends "Hello", "Hello", and "How about an answer?".
With byte stream protocols, the server can receive as "Hell", "oHelloHow", and " about an answer?"; or more realistically "HelloHelloHow about an answer?". The server has no clue where the message boundary is.
An age old trick is to limit the message length to
CHAR_MAX
orUINT_MAX
and agree to send the message length first inchar
oruint
. So, if you are at the receiving side, you have to read the message length first. This also implies that only one thread should be doing the message reading at a time.With discrete protocols like UDP or message queues, you don't have to worry about this issue, but programmatically byte streams are easier to deal with because they behave like files and stdin/out.
共享内存可能是最有效的,因为您可以在其之上构建自己的通信方案,但它需要大量的关注和同步。 也可以使用将共享内存分配给其他机器的解决方案。
套接字是当今最便携的,但需要比管道更多的开销。 能够在本地或通过网络透明地使用套接字是一个很大的好处。
消息队列和信号对于硬实时应用程序来说非常有用,但它们不够灵活。
这些方法自然是为了进程之间的通信而创建的,并且在进程中使用多个线程可能会使事情变得复杂——尤其是对于信号而言。
Shared memory can be the most efficient since you build your own communication scheme on top of it, but it requires a lot of care and synchronization. Solutions are available for distributing shared memory to other machines too.
Sockets are the most portable these days, but require more overhead than pipes. The ability to transparently use sockets locally or over a network is a great bonus.
Message queues and signals can be great for hard real-time applications, but they are not as flexible.
These methods were naturally created for communication between processes, and using multiple threads within a process can complicate things -- especially with signals.
这是一个带有简单基准的网页: https://sites.google.com/site/rikkus/sysv-ipc-vs-unix-pipes-vs-unix-sockets
据我所知,每个都有其优点:
没有固有的消息边界。
并且没有固有的消息边界。
Here is a webpage with a simple benchmark: https://sites.google.com/site/rikkus/sysv-ipc-vs-unix-pipes-vs-unix-sockets
As far as I can tell, each has their advantages:
no inherent message boundaries.
and no inherent message boundaries.
值得注意的是,许多库在一种类型的事物之上实现另一种类型的事物。
共享内存不需要使用可怕的 sysv 共享内存函数 - 使用 mmap() 更优雅(如果您想要命名,则将文件映射到 tmpfs /dev/shm 上;如果您想要,则使用 mmap /dev/zero分叉未执行的进程以匿名继承它)。 话虽如此,您的进程仍然需要进行一些同步以避免出现问题 - 通常通过使用一些其他 IPC 机制来同步对共享内存区域的访问。
It's worth noting that lots of libraries implement one type of thing on top of another.
Shared memory doesn't need to use the horrible sysv shared memory functions - it's much more elegant to use mmap() (mmap a file in on a tmpfs /dev/shm if you want it named; mmap /dev/zero if you want forked not exec'd processes to inherit it anonymously). Having said that, it still leaves your processes with some need for synchronisation to avoid problems - typically by using some of the other IPC mechanisms to do synchronisation of access to a shared memory area.