2. HSMS通信基础:HSMS协议定义、TCP/IP连接建立、会话管理与心跳机制

HSMS(High-Speed SECS Message Services)是SECS/GEM协议栈中负责底层通信的核心协议。它定义了如何在TCP/IP网络上传输SECS消息,是连接设备与主机(MES)的通信桥梁。本章将深入解析HSMS协议的定义、连接建立过程、会话管理机制以及心跳保活策略。

核心要点: HSMS并非独立于SECS-II,而是SECS-II在TCP/IP网络上的传输载体。理解HSMS是掌握设备与MES系统高效、可靠通信的前提。

2.1 HSMS协议定义与报文结构

HSMS协议规范了在TCP/IP连接上传输SECS消息的格式和规则。其核心是HSMS报文,它由报文头和报文体(即SECS-II消息)组成。

2.1.1 HSMS报文头结构

HSMS报文头固定为10字节,是通信控制的关键。其结构如下表所示:

字节偏移 字段名称 长度(字节) 描述
0-3 Length 4 报文总长度(包含报文头+报文体),以大端序表示。
4 Device ID 1 设备ID,用于标识通信的源或目标设备。
5 Stream 1 SECS-II消息的流(Stream)号。
6 Function 1 SECS-II消息的功能(Function)号。
7 PType 1 报文类型(Packet Type),0x00表示数据消息。
8 SType 1 会话类型(Session Type),0x00表示数据消息,其他值表示控制消息。
9 System Bytes 1 系统字节,用于消息匹配和事务跟踪。
开发提示: 在解析HSMS报文时,务必注意Length字段是大端序(Big-Endian)。在x86架构的系统中,需要进行字节序转换。

2.1.2 HSMS报文类型

HSMS定义了两种主要的报文类型:

  • 数据消息(Data Message): 用于传输SECS-II消息(如S1F1、S2F17等)。PType=0x00,SType=0x00。
  • 控制消息(Control Message): 用于管理HSMS连接本身,如建立连接、断开连接、心跳等。PType=0x00,SType非0。

常见的控制消息SType值如下:

SType值 消息名称 描述
0x01 Select.req 请求建立会话(连接)
0x02 Select.rsp 会话建立响应
0x05 Deselect.req 请求断开会话
0x06 Deselect.rsp 会话断开响应
0x09 Linktest.req 心跳请求(链路测试)
0x0A Linktest.rsp 心跳响应
0x0B Reject.req 拒绝请求

2.2 TCP/IP连接建立

HSMS通信建立在TCP/IP连接之上。设备与主机(MES)之间通过三次握手建立TCP连接,然后通过HSMS控制消息建立逻辑会话。

2.2.1 连接模式:主动与被动

在HSMS中,设备可以配置为两种角色:

  • 主动模式(Active): 设备主动向主机发起TCP连接请求。
  • 被动模式(Passive): 设备监听端口,等待主机发起连接。

通常,设备作为主动方,主机作为被动方。连接建立后,双方即可进行双向通信。

2.2.2 连接建立流程

一个完整的HSMS连接建立过程分为两个阶段:

  1. TCP三次握手: 建立底层的TCP连接。
  2. HSMS Select过程: 通过控制消息建立逻辑会话。

下图展示了HSMS连接建立的完整流程:

HSMS连接建立流程 设备 (Active) 主机 (Passive) ① TCP SYN ② TCP SYN-ACK ③ TCP ACK TCP连接建立成功 ④ Select.req (SType=0x01) ⑤ Select.rsp (SType=0x02) HSMS会话建立成功,可传输数据 ⑥ 数据消息 (SECS-II) ⑦ 数据消息 (SECS-II)
开发要点: Select.req消息中的Device ID字段必须与设备配置一致。主机在Select.rsp中返回状态码,0x00表示成功,其他值表示失败原因。

2.3 会话管理

HSMS会话(Session)是建立在TCP连接之上的逻辑通信通道。一个TCP连接可以承载多个会话,但在实际应用中,通常一个TCP连接对应一个会话。

2.3.1 会话状态机

HSMS会话具有明确的状态转换,主要包括:

  • Not Selected: 初始状态,TCP已连接但未建立会话。
  • Selected: 会话已建立,可以传输数据消息。
  • Deselected: 会话已断开,但仍可重新建立。

2.3.2 会话断开流程

当设备或主机需要断开通信时,会执行Deselect过程:

  1. 发起方发送Deselect.req控制消息。
  2. 接收方回复Deselect.rsp确认断开。
  3. 会话状态回到Not Selected。
  4. 可选择关闭TCP连接。
注意事项: 在断开会话前,应确保所有未完成的事务(Transaction)已处理完毕,否则可能导致数据丢失或状态不一致。

2.4 心跳机制(Linktest)

心跳机制是HSMS协议中用于检测连接是否存活的重要功能。它通过定期发送Linktest.req和Linktest.rsp控制消息来验证通信链路。

2.4.1 心跳工作原理

心跳机制的工作流程如下:

  1. 设备或主机启动一个定时器,周期性地发送Linktest.req消息。
  2. 接收方收到后,立即回复Linktest.rsp消息。
  3. 如果发送方在超时时间内未收到响应,则认为连接已断开,并触发重连机制。

2.4.2 心跳参数配置

在实际开发中,以下参数需要合理配置:

参数名称 推荐值 说明
Linktest Interval 10-30秒 发送Linktest.req的间隔时间
Linktest Timeout 5-10秒 等待Linktest.rsp的超时时间
Retry Count 3次 连续超时次数后判定连接断开

2.4.3 心跳机制流程图

HSMS心跳机制(Linktest) 设备 主机 定时器触发 Linktest.req (SType=0x09) 回复Linktest.rsp Linktest.rsp (SType=0x0A) 连接正常 超时未收到响应 触发重连机制
最佳实践: 在MES系统集成中,建议将心跳间隔设置为15秒,超时时间设置为8秒。这样既能及时发现网络故障,又不会因过于频繁的心跳增加网络负担。

2.5 代码示例:HSMS报文解析

以下是一个简单的C语言示例,演示如何解析HSMS报文头:

#include <stdint.h>
#include <arpa/inet.h>

typedef struct {
    uint32_t length;      // 报文总长度
    uint8_t  device_id;   // 设备ID
    uint8_t  stream;      // Stream号
    uint8_t  function;    // Function号
    uint8_t  ptype;       // 报文类型
    uint8_t  stype;       // 会话类型
    uint8_t  system_bytes;// 系统字节
} hsms_header_t;

int parse_hsms_header(const uint8_t *buffer, hsms_header_t *header) {
    if (buffer == NULL || header == NULL) {
        return -1;
    }

    // 读取Length字段(大端序转主机字节序)
    header->length = ntohl(*(uint32_t *)buffer);
    header->device_id = buffer[4];
    header->stream = buffer[5];
    header->function = buffer[6];
    header->ptype = buffer[7];
    header->stype = buffer[8];
    header->system_bytes = buffer[9];

    return 0;
}

// 使用示例
void example_usage() {
    uint8_t raw_data[10] = {
        0x00, 0x00, 0x00, 0x0A,  // Length = 10
        0x01,                     // Device ID = 1
        0x01,                     // Stream = 1
        0x01,                     // Function = 1
        0x00,                     // PType = 0 (Data Message)
        0x00,                     // SType = 0 (Data Message)
        0x00                      // System Bytes = 0
    };

    hsms_header_t header;
    if (parse_hsms_header(raw_data, &header) == 0) {
        printf("HSMS Header Parsed:\n");
        printf("  Length: %u\n", header.length);
        printf("  Device ID: %u\n", header.device_id);
        printf("  Stream: %u\n", header.stream);
        printf("  Function: %u\n", header.function);
        printf("  PType: 0x%02X\n", header.ptype);
        printf("  SType: 0x%02X\n", header.stype);
        printf("  System Bytes: %u\n", header.system_bytes);
    }
}
代码说明: 上述代码中,ntohl()函数用于将网络字节序(大端)转换为主机字节序。在解析HSMS报文时,这是必须的步骤。

2.6 常见问题与避坑指南

  • 问题1: TCP连接建立成功,但Select.req失败。
    原因: Device ID不匹配或主机未准备好。
    解决: 检查设备配置中的Device ID,并确认主机服务已启动。
  • 问题2: 心跳超时导致频繁重连。
    原因: 网络延迟高或心跳间隔设置过短。
    解决: 适当增加心跳间隔和超时时间,或优化网络环境。
  • 问题3: 报文解析错误,数据乱码。
    原因: 未正确处理字节序或报文长度计算错误。
    解决: 严格遵循大端序解析,并验证Length字段与实际接收数据长度一致。
重要提醒: 在生产环境中,务必实现完善的连接状态监控和自动重连机制。HSMS通信的稳定性直接影响到MES系统与设备之间的数据完整性。