3. HSMS 报文结构:消息头(Message Header)解析
HSMS(High-Speed SECS Message Services)是 SECS/GEM 协议在 TCP/IP 网络上的传输层实现。理解 HSMS 报文结构是进行报文捕获与协议解析的基础。每一个 HSMS 报文都由一个固定长度的 消息头(Message Header) 和紧随其后的 数据区(Data Block) 组成。消息头承载了会话控制、消息路由和事务管理的关键信息。
核心要点: HSMS 消息头固定为 14 字节(4 字节长度 + 10 字节头部字段),这是解析任何 HSMS 报文的起点。长度字段决定了整个报文(包括头部本身)的字节数。
3.1 HSMS 报文整体结构
一个完整的 HSMS 报文在 TCP 流中呈现为“长度前缀 + 消息头 + 数据区”的格式。长度前缀是一个 4 字节的无符号整数,用于帧定界。
3.2 消息头(Message Header)字段详解
消息头固定为 10 字节,包含 5 个关键字段。下表列出了每个字段的偏移、长度、名称和用途。
| 偏移(字节) | 长度(字节) | 字段名称 | 描述 |
|---|---|---|---|
| 0 | 2 | Session ID(会话 ID) | 标识设备或会话。设备端通常为 0,主机端为 1–32767。 |
| 2 | 1 | Header Byte 2(头部字节 2) | 包含 RTS(请求/响应)标志位和事务类型。 |
| 3 | 1 | Header Byte 3(头部字节 3) | 包含消息类型(Message Type)编码。 |
| 4 | 4 | System Bytes(系统字节) | 用于匹配请求与响应的事务 ID。 |
| 8 | 2 | Reserved / Data Length(保留/数据长度) | 通常为 0x0000;在部分实现中用于指示数据区长度。 |
调试技巧: 在 Wireshark 或 SECS 调试工具中,直接查看消息头的 10 个字节即可快速判断会话归属、消息方向和事务类型。System Bytes 是追踪“请求-响应”对的关键。
3.3 长度字段(Length Field)
长度字段位于报文最前端,占用 4 字节(32 位无符号整数,网络字节序)。它表示从消息头开始到报文结束的总字节数,即 10 + N(N 为数据区长度)。
- 最小值: 10(无数据区,仅消息头)。
- 最大值: 理论 2³²-1,但实际受 TCP 缓冲区限制。
- 解析要点: 接收方先读取 4 字节得到长度 L,再读取 L 字节得到完整的消息头+数据区。
// 伪代码:HSMS 报文接收逻辑
uint32_t length = read_uint32_big_endian(socket); // 读取 4 字节长度
uint8_t* buffer = malloc(length);
read_exactly(socket, buffer, length); // 读取完整报文
// buffer[0..9] 为消息头,buffer[10..length-1] 为数据区
3.4 会话 ID(Session ID)
Session ID 占用消息头的前 2 字节(偏移 0–1),用于区分不同的通信会话。在单会话模式下,设备端固定为 0,主机端通常为 1。在多会话模式下,该字段用于路由到正确的逻辑设备。
3.5 消息类型(Message Type)
消息类型编码位于消息头的第 4 字节(偏移 3),用于区分 HSMS 控制消息和 SECS 数据消息。下表列出了常见的消息类型值。
| 消息类型值(十进制) | 消息类型名称 | 方向 | 说明 |
|---|---|---|---|
| 0 | Data Message | 双向 | 携带 SECS-II 数据(如 S1F1、S6F11 等) |
| 1 | Select.req | 设备→主机 | 请求建立会话连接 |
| 2 | Select.rsp | 主机→设备 | 会话建立响应 |
| 3 | Deselect.req | 双向 | 请求断开会话 |
| 4 | Deselect.rsp | 双向 | 断开会话响应 |
| 5 | Linktest.req | 双向 | 连接测试请求 |
| 6 | Linktest.rsp | 双向 | 连接测试响应 |
| 9 | Reject.req | 双向 | 拒绝非法报文 |
| 10 | Separate.req | 双向 | 分离连接(优雅关闭) |
常见误区: 消息类型 0(Data Message)并不等于 SECS-II 消息本身。它仅表示“这是一个数据报文”,具体是 S1F1 还是 S6F11 需要解析数据区中的 SECS-II 流。不要将消息类型与 Stream/Function 混淆。
3.6 系统字节(System Bytes)
系统字节占用消息头的第 5–8 字节(偏移 4–7),共 4 字节。它是一个由发送方生成的唯一事务标识符,用于将响应报文与对应的请求报文匹配。
- 生成规则: 通常使用递增计数器或时间戳的低 32 位。
- 匹配机制: 响应报文必须复制请求报文的 System Bytes 值。
- 调试价值: 在捕获的报文中,通过 System Bytes 可以快速找到“请求-响应”对。
// 示例:System Bytes 匹配逻辑
// 请求报文(设备→主机): System Bytes = 0x00001234
// 响应报文(主机→设备): System Bytes = 0x00001234 ← 必须相同
// 如果 System Bytes 不匹配,说明响应与请求不对应,可能是超时重传或乱序。
3.7 完整报文解析示例
下面是一个实际的 HSMS 报文十六进制转储及其解析过程。
原始字节(十六进制):
00 00 00 0E 00 01 81 00 00 00 00 01 00 00
解析步骤:
1. 长度字段(4 字节): 00 00 00 0E → 14 字节(整个报文长度)
2. 消息头(10 字节):
- Session ID: 00 01 → 1(主机会话)
- Header Byte 2: 81 → RTS=1(响应),事务类型=1
- Header Byte 3: 00 → 消息类型=0(Data Message)
- System Bytes: 00 00 00 01 → 1
- Reserved: 00 00
3. 数据区(4 字节): 后续字节为 SECS-II 数据(本例省略)
实战要点: 在 Wireshark 中,HSMS 解析器会自动将长度字段、消息头各字段拆解显示。手动解析时,务必注意网络字节序(Big-Endian)和字段边界对齐。
3.8 消息头字段速查表
下表汇总了消息头各字段的字节偏移、取值范围和常见值,方便现场调试时快速对照。
| 字段 | 偏移 | 长度 | 取值范围 | 常见值 |
|---|---|---|---|---|
| Session ID | 0 | 2 | 0–65535 | 0(设备),1(主机) |
| Header Byte 2 | 2 | 1 | 0x00–0xFF | 0x81(响应+事务类型1) |
| Header Byte 3 | 3 | 1 | 0–10 | 0(Data Message) |
| System Bytes | 4 | 4 | 0–2³²-1 | 递增计数器 |
| Reserved | 8 | 2 | 通常为 0 | 0x0000 |