本地IPC,POSIX消息队列(mqueues)和Unix域(local)套接字哪个更好?

29

在本地进程间通信(IPC)中,使用POSIX消息队列还是Unix域套接字更好?

我曾经使用Unix套接字在不同机器之间进行过工作,并且记得建立和断开连接会导致套接字在最终消失之前会残留一段时间。此外,如果您想要一个“可靠”的交换,您要么必须使用TCP,要么就要设计应用程序返回一个ACK。但我不确定这是否也适用于Unix域套接字。

在我的当前项目中,我们需要进行本地IPC。我的第一反应是使用POSIX MQueues,因为我之前已经用过它们进行本地消息传递。然而,我的同事建议使用Unix域套接字。

其中一个比另一个更好,还是只是取决于编程熟练程度?或者可能取决于正在创建的应用程序?

从大局来看,我们正在开发的应用程序遵循客户端/服务器模型。客户端向服务器发送消息以“执行某些操作”。然而,客户端不会等待“完成”的响应--尽管他们确实想知道他们的请求是否已被接收。

发送方的基本逻辑是:

connect to server
send request
note if the send worked or not
disconnect from server

一个服务器可以连接上数百个客户端。

我们正在运行Linux操作系统的SMP系统上(4-8个核心)执行。

提前致谢。

3个回答

10

UNIX域套接字不必像TCP协议中那样保持在"TIME_WAIT"状态,因为这段等待时间是用于防止连接中还有漂浮的数据包。但这种情况在本地并不存在。

UNIX域套接字可以是SOCK_STREAM(类似于TCP)或者SOCK_DGRAM(类似于UDP),并且UNIX域数据报套接字具有可靠性和不重排序数据报的额外保证。

如果你想要确保另一个应用程序已经读取了你发送的消息,你仍然需要一些形式的确认(即使使用TCP)。毕竟,即使send()成功了,它也可能在处理消息之前崩溃。(这也适用于消息队列 - 为了确保消息不会丢失,接收应用程序必须将请求写入日志、将其刷新到磁盘,然后发送回确认)。

我同意选择基本上是编程熟悉度的问题。


8
有人认为其中一种比另一种更好,还是说这取决于编程熟悉度?或者这取决于正在创建的应用程序?
据我所知,SysV消息队列与UNIX域数据报套接字相比有以下主要区别:
- 您可以使用 poll()套接字,但不能使用消息队列。 - 消息队列是全局的,通常需要一些管理参与:清除旧的挂起SysV资源是许多系统管理员日常工作之一。而UNIX域的语义要简单得多,应用程序通常可以在不涉及系统管理员的情况下完全内部维护它。 - 消息队列是持久的,可能会保留来自旧会话的消息。(不能精确回忆那一点,但我记得我经历过这种情况)。 - 查看 man msgrcv ,我没有看到套接字的 MSG_PEEK 等效项。很少需要,但有时非常方便。 - 大多数时间,用户喜欢在配置中使用符号名称,而不是数字键ID。缺乏符号键,我认为是SysV界面设计师的一个严重疏漏。
与所有SysV资源一样,它们的管理是主要的烦恼。如果您让系统决定消息队列ID,则必须确保与其他应用程序正确共享它。 (您还必须以某种方式告诉管理员ID最终必须被删除)。如果允许为消息队列配置密钥,则可能会遇到微不足道的问题,即ID已被某些应用程序使用或者它是上一次运行的残留物。 (看到服务器因SysV资源耗尽而重新启动非常普遍。)
总而言之,我在可能的情况下避免使用SysV资源:在大多数常见情况下缺乏 poll()支持是无法接受的。
然而,客户端不等待“完成”响应-尽管他们确实想知道他们的请求是否已被接收。
这是事务处理的常见困境。通常的回应是(如在RDBMS中)你不能,通信中断(崩溃或其他原因)后,应用程序必须自己检查请求是否已经被处理。
从这可以看出,TCP可能是更好的选择。客户端发送请求,并在从服务器获得正面响应时将其声明为已完成。除非服务器能够将响应发送给客户端,否则必须回滚事务。

2
在Linux上,POSIX消息队列描述符实际上是一个文件描述符,并支持select/poll。我不确定System V消息队列是否也是如此。 - nos
@nos:参考资料?你是不是把它和AIX混淆了?POSIX没有描述那个,我知道的旧Linux参考资料也说没有。 - Dummy00001
5
在Linux中,消息队列描述符实际上是文件描述符,并且可以使用select(2),poll(2)或epoll(7)进行监视。这种方法不可移植。这是针对POSIX消息队列的说明,我不确定SysV消息队列是否也是这样工作的,如果是的话可能在最近几年发生了变化。 - nos
@nos:谢谢。这就解释了为什么有两个接口。mq_*函数是新的POSIX接口:“首次发布于第5版。包括与POSIX实时扩展的对齐。”然而,POSIX并没有定义使用poll()与“消息队列描述符”的用法... :( - Dummy00001

4
我建议使用DBus开发这样的应用程序,主要是因为它具有数据编组和RPC类似接口(同步和异步都支持)。DBus本身原生支持域套接字,并且在经过初始学习曲线后,运行非常稳定。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接