Skip to content

zmq_socket_monitor 监控模式未关闭导致的阻塞问题

问题背景

在使用 ZeroMQ 的 ZMQ_STREAM 套接字并启用监控(monitor)功能时,若仅关闭用于接收监控事件的 ZMQ_PAIR 套接字,而不显式停止监控模式,会导致 ZeroMQ 内部后台线程永久阻塞。


错误操作流程

  1. 创建一个 ZMQ_STREAM 套接字。
  2. 调用 zmq_socket_monitor() 启用监控模式,并打开对应的 ZMQ_PAIR 套接字用于接收事件。
  3. ZMQ_STREAM 套接字连接到某个 TCP 服务器。
  4. 错误做法:直接关闭 ZMQ_PAIR 套接字,认为这足以停止监控。
  5. 关闭 TCP 服务器。

导致的问题

  • 当 TCP 连接断开时,ZeroMQ 会尝试通过内部持有的 ZMQ_PAIR 套接字发送 ZMQ_EVENT_DISCONNECTED 事件。
  • 但由于用户已关闭该 ZMQ_PAIR 套接字,无人读取该事件,导致 ZeroMQ 后台线程在 zmq::socket_base_t::monitor_event() 中永久阻塞。
  • 程序无法正常退出,出现“挂死”现象。

正确解决方案

在关闭 ZMQ_PAIR 套接字 之前,必须先调用:

c
zmq_socket_monitor(my_stream_socket, NULL, 0);
  • 该调用会显式停用监控模式,释放内部资源,避免后续事件发送。
  • 虽然 zmq_socket_monitor() 支持传入 NULL 作为 endpoint 来停止监控,但此用法在官方文档中未被说明,属于隐藏行为。

建议

  • 在使用 zmq_socket_monitor() 时,务必成对操作:启动监控 → 使用 → 显式停止监控(传 NULL)→ 关闭监控套接字。、

环境信息:libzmq 4.3.1,Linux
参考链接GitHub Issue #3575

企业微信截图_17666305215700.png

image.png

image.png

基于 VitePress 构建