【问题标题】:Which is better for local IPC, POSIX message queues (mqueues) or Unix domain (local) sockets?哪个更适合本地 IPC、POSIX 消息队列 (mqueues) 或 Unix 域 (本地) 套接字?
【发布时间】:2011-04-16 00:26:12
【问题描述】:

本地 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 核)上执行。

提前致谢。

【问题讨论】:

    标签: c++ c sockets ipc posix


    【解决方案1】:

    UNIX 域套接字不必“徘徊”在类似TIME_WAIT 的状态,因为该等待时间用于防止来自连接的杂散数据包仍在 Internet 上徘徊。该问题不适用于本地。

    UNIX 域套接字可以是 SOCK_STREAM(如 TCP)或 SOCK_DGRAM(如 UDP),并额外保证 UNIX 域数据报套接字是可靠的并且不会重新排序数据报。

    如果您想确定您的其他应用程序已读取您发送的消息,您仍然需要某种 ACK(即使使用 TCP);毕竟,即使send() 成功了,它也可能在有机会处理消息之前就崩溃了。 (这也适用于消息队列——为了完全确保消息不会丢失,接收应用程序必须将请求写入日志,将其刷新到磁盘,然后发回确认)。

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

    【讨论】:

      【解决方案2】:

      是一个比另一个更好,还是编程熟悉度的问题?或者它可能取决于正在创建的应用程序?

      SysV 消息队列与 UNIX 域数据报套接字相比具有我所知道的主要区别:

      • 你可以poll()socket,但你不能消息队列。

      • 消息队列是全局的,可能(并且通常会)需要一些管理参与:清理旧的挂起的 SysV 资源是许多系统管理员日常工作之一。虽然 UNIX 域的语义要简单得多,并且应用程序通常可以在内部完全维护它,而无需系统管理员参与。

      • (?) 消息队列是持久的,它可能会保留来自旧会话的消息。 (记不太清了,但 IIRC 不止一次发生在我身上)。

      • 看着man msgrcv,我看不到套接字MSG_PEEK 的类似物。很少需要,但有时很方便。

      • 大多数时候,用户更喜欢在配置中使用符号名称,而不是数字键 ID。 IMO 缺少符号键是对部分 SysV 界面设计者的严重疏忽。

      与所有 SysV 资源一样,它们的管理是主要的 PITA。如果您让系统决定消息队列 ID,那么您必须注意与其他应用程序正确共享它。 (而且您还必须以某种方式告诉管理员最终必须删除该 ID)。如果您允许为消息队列配置密钥,那么您可能会遇到一些小问题,即 id 已被某些应用程序使用,或者它是前一次运行的残余。 (看到服务器仅因为 SysV 资源耗尽而重新启动是很常见的。)

      总而言之,我尽可能避免使用 SysV 资源:在大多数情况下缺乏 poll() 支持会破坏交易。

      但是,客户端不会等待“完成”响应——尽管他们确实想知道他们的请求是否已收到。

      这是事务处理的常见困境。一般响应是(如在 RDBMS 中)您不能,并且在通信中断(崩溃或其他)之后,应用程序必须检查自己是否已处理请求。

      据我所知,TCP 可能是一个更好的选择。客户端仅在收到服务器的肯定响应时才发送请求并声明它已完成。除非服务器能够向客户端发送响应,否则必须回滚事务。

      【讨论】:

      • 虽然,在 Linux 上,posix 消息队列描述符实际上是一个文件描述符,它支持选择/轮询。我不确定 sysv 消息队列。
      • @nos:参考?你不是把它和AIX混在一起吗? POSIX 没有描述这一点,old Linux reference I know 也说不。
      • man mq_overview, "在 Linux 上,消息队列描述符实际上是一个文件描述符,可以使用 select(2)、poll(2) 或 epoll(7) 进行监控。这不可移植。” ,如前所述,这是 posix 消息队列,我不确定 sysv 消息队列是否以这种方式工作,如果他们这样做,近年来发生了变化。
      • @nos:谢谢。这就解释了为什么有两个接口。 mq_* 函数是 the new POSIX interface:“在第 5 期中首次发布。包含用于与 POSIX 实时扩展保持一致。”然而 POSIX 并没有定义 poll() 与“消息队列描述符”的使用...... :(
      【解决方案3】:

      我建议为这样的应用程序查看 DBus,如果只是为了他们的数据编组和类似 RPC 的接口(同步和异步)。它在本地使用域套接字,并且在经过初步学习曲线后工作得非常好。

      【讨论】:

        猜你喜欢
        • 2011-06-01
        • 2018-10-14
        • 2013-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-30
        • 1970-01-01
        • 2014-07-24
        相关资源
        最近更新 更多