Skip to content

ZeroMQ socket monitor 事件对照表 ​

ZeroMQ 的 zmq_socket_monitor() 可以为套接字挂一个监控通道,上报连接建立、断开、握手等事件。事件以位掩码表示,而日志和回调里拿到的一般只有十进制数值(例如 Monitor event: 128),不看宏定义很难知道发生了什么。本文给出全部事件的十六进制/十进制对照、event_value 在不同事件下的语义,以及一段日志解析示例。数值已逐一核对 libzmq include/zmq.h(master 分支,2026-10),适用于 4.x 系列。

事件对照表 ​

事件宏定义 十六进制值 十进制值 说明
ZMQ_EVENT_CONNECTED 0x0001 1 成功建立出站连接(TCP 连接完成)
ZMQ_EVENT_CONNECT_DELAYED 0x0002 2 连接被延迟(例如无可用 I/O 线程)
ZMQ_EVENT_CONNECT_RETRIED 0x0004 4 连接失败后重试(含重试间隔)
ZMQ_EVENT_LISTENING 0x0008 8 成功绑定并开始监听(bind() 成功)
ZMQ_EVENT_BIND_FAILED 0x0010 16 绑定失败(如端口被占用)
ZMQ_EVENT_ACCEPTED 0x0020 32 接受入站连接(TCP accept 成功)
ZMQ_EVENT_ACCEPT_FAILED 0x0040 64 接受连接失败(如资源不足)
ZMQ_EVENT_CLOSED 0x0080 128 套接字成功关闭
ZMQ_EVENT_CLOSE_FAILED 0x0100 256 套接字关闭失败
ZMQ_EVENT_DISCONNECTED 0x0200 512 连接断开(对端关闭或网络中断)
ZMQ_EVENT_MONITOR_STOPPED 0x0400 1024 监控被停止(调用 zmq_socket_monitor(..., NULL, ...))
ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL 0x0800 2048 握手失败,无详细原因(通常为系统级错误)
ZMQ_EVENT_HANDSHAKE_SUCCEEDED 0x1000 4096 ZMTP 握手成功(含认证成功)
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL 0x2000 8192 协议错误
ZMQ_EVENT_HANDSHAKE_FAILED_AUTH 0x4000 16384 认证失败
ZMQ_EVENT_ALL 0xFFFF 65535 所有事件的掩码(用于启用全部监控)

每个事件以两帧消息发送:第一帧含 16 位事件号与 32 位事件值,第二帧为受影响 endpoint 的字符串。

event_value 的语义随事件变化 ​

event_value 字段在不同事件中含义不同,排查时要按事件类型解读:

  • CONNECTED、LISTENING、ACCEPTED → 文件描述符;
  • CONNECT_RETRIED → 重试间隔(毫秒);
  • BIND_FAILED、ACCEPT_FAILED、HANDSHAKE_FAILED_NO_DETAIL → errno;
  • HANDSHAKE_FAILED_PROTOCOL → ZMQ_PROTOCOL_ERROR_* 之一(见下表);
  • HANDSHAKE_FAILED_AUTH → ZAP 状态码(300 = 临时拒绝,400 = 无效请求,500 = 内部错误);
  • CLOSE_FAILED 仅在 IPC 传输下出现。

协议错误子类型 ​

ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL(8192)的 event_value 取以下值:

错误宏定义 十六进制值 十进制值 说明
ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED 0x10000000 268435456 未指定的 ZMTP 错误
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND 0x10000001 268435457 收到意外的 ZMTP 命令
ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE 0x10000002 268435458 ZMTP 命令序列无效
ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE 0x10000003 268435459 密钥交换失败(CURVE)
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO 0x10000013 268435475 HELLO 命令格式错误
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE 0x10000014 268435476 INITIATE 命令格式错误
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC 0x11000001 285212673 加密操作失败(如密钥无效)
ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH 0x11000002 285212674 安全机制不匹配(如一端用 CURVE,另一端未启用)
ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED 0x20000000 536870912 ZAP(认证代理)未指定错误
ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY 0x20000001 536870913 ZAP 回复格式错误
ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION 0x20000003 536870915 ZAP 版本不支持

ZMQ_PROTOCOL_ERROR_* 的十进制值较大(2.6 亿以上),日志里看到这类数字可直接按前缀识别:0x1xxxxxxx 为 ZMTP 层,0x2xxxxxxx 为 ZAP 层。

日志解析示例 ​

把事件号映射为可读名字,是排查 monitor 相关问题时最常用的手段:

cpp
void handle_monitor_event(uint16_t event, const char *addr) {
    static const std::unordered_map<uint16_t, std::string> event_names = {
        {1, "CONNECTED"},        {2, "CONNECT_DELAYED"},
        {4, "CONNECT_RETRIED"},  {8, "LISTENING"},
        {16, "BIND_FAILED"},     {32, "ACCEPTED"},
        {64, "ACCEPT_FAILED"},   {128, "CLOSED"},
        {256, "CLOSE_FAILED"},   {512, "DISCONNECTED"},
        {1024, "MONITOR_STOPPED"},
        {2048, "HANDSHAKE_FAILED_NO_DETAIL"},
        {4096, "HANDSHAKE_SUCCEEDED"},
        {8192, "HANDSHAKE_FAILED_PROTOCOL"},
        {16384, "HANDSHAKE_FAILED_AUTH"},
    };

    auto it = event_names.find(event);
    std::string name = (it != event_names.end()) ? it->second : "UNKNOWN";
    LOG_DEBUG << "Monitor event: " << event << " (" << name << ") at " << addr;
}

版本注意事项 ​

  • 所有事件值均为位掩码,可组合使用(如 ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED)。
  • ZMQ_EVENT_ALL(0xFFFF)只涵盖上表前 16 个事件;官方文档同时提醒,随着新事件加入,这个「全集」值会自动包含新事件,依赖固定事件序列的应用不应使用它。
  • libzmq master 分支已新增 ZMQ_EVENT_PIPES_STATS(0x10000)与 ZMQ_EVENT_ALL_V2(ALL_V1 | PIPES_STATS),此时 ZMQ_EVENT_ALL 不再涵盖全部事件;上表其余值与 4.3.x 一致。

核对依据为 libzmq 仓库 include/zmq.h 与 zmq_socket_monitor(3) 官方文档。

最近更新

基于 VitePress 构建