zmq_socket_monitor 监控模式未关闭导致的阻塞问题
问题背景
在使用 ZeroMQ 的 ZMQ_STREAM 套接字并启用监控(monitor)功能时,若仅关闭用于接收监控事件的 ZMQ_PAIR 套接字,而不显式停止监控模式,会导致 ZeroMQ 内部后台线程永久阻塞。
错误操作流程
- 创建一个
ZMQ_STREAM套接字。 - 调用
zmq_socket_monitor()启用监控模式,并打开对应的ZMQ_PAIR套接字用于接收事件。 - 将
ZMQ_STREAM套接字连接到某个 TCP 服务器。 - 错误做法:直接关闭
ZMQ_PAIR套接字,认为这足以停止监控。 - 关闭 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


