4. Not Selected 状态详解:初始状态特征、监听与连接请求处理、超时与重试机制
Not Selected 状态是 HSMS 连接状态机中的初始状态,也是所有 TCP 连接建立后的第一个稳定状态。在该状态下,通信双方尚未完成 Select (S) 或 Select with Data (S6F1/S6F2) 等会话建立流程,因此不能进行任何 SECS-II 消息的交换。本章将深入分析 Not Selected 状态的核心特征、监听与连接请求处理逻辑,以及 T3 超时在该状态下的特殊行为与恢复策略。
关键概念: Not Selected 状态是 HSMS 连接的生命周期起点,也是状态机中最“脆弱”的阶段——任何 T3 超时或连接异常都会导致状态回退或连接断开。
4.1 初始状态特征
当 TCP 连接成功建立后,HSMS 实体自动进入 Not Selected 状态。该状态具有以下特征:
- 无会话上下文: 设备 ID、控制块 ID、消息序列号等会话参数均未初始化。
- 仅允许控制消息: 只能发送和接收 HSMS 控制消息(如 Select.req、Select.rsp、Linktest.req、Linktest.rsp),禁止任何 SECS-II 数据消息。
- T3 超时激活: 当发送 Select.req 后,T3 定时器启动,等待 Select.rsp 响应。
- 连接可被关闭: 任何一方可在 Not Selected 状态下主动发起 Disconnect.req 关闭连接。
| 属性 | Not Selected 状态值 | 说明 |
|---|---|---|
| 会话 ID | 未分配 | 设备 ID 尚未协商 |
| 允许消息类型 | 仅控制消息 | Select.req/rsp, Linktest.req/rsp, Disconnect.req/rsp |
| T3 定时器 | 激活(发送 Select.req 后) | 默认 45 秒,可配置 |
| 连接保持 | TCP 连接保持打开 | 等待 Select 流程完成 |
| 状态转换目标 | Selected 或 Disconnected | 成功则进入 Selected,失败则断开 |
工程提示: 在 Not Selected 状态下,如果收到非控制消息(如 SECS-II 数据消息),接收方应直接丢弃并记录错误日志,不应触发任何状态转换。
4.2 监听与连接请求处理
在 Not Selected 状态下,HSMS 实体需要同时处理两种角色:主动连接方(Active) 和 被动监听方(Passive)。两种角色的行为差异主要体现在 Select 流程的发起时机上。
4.2.1 主动连接方(Active)
主动方在 TCP 连接建立后,立即发送 Select.req 控制消息,并启动 T3 定时器。Select.req 消息包含以下关键字段:
Message Header:
Session ID: 0xFFFF (未选择)
Stream: 0x00
Function: 0x01 (Select.req)
PType: 0x00 (控制消息)
SType: 0x01 (Select)
System Bytes: 0x00000001 (递增序列号)
主动方在发送 Select.req 后,进入 等待 Select.rsp 的子状态。在此期间,主动方可以接收 Linktest.req 并回复 Linktest.rsp,但不会处理其他控制消息。
4.2.2 被动监听方(Passive)
被动方在 TCP 连接建立后,不会主动发送任何消息,而是等待接收 Select.req。当收到 Select.req 后,被动方执行以下步骤:
- 验证 Select.req 的格式和系统字节是否合法。
- 检查设备 ID 是否已被其他连接占用(如果设备 ID 在 Select.req 中指定)。
- 分配会话资源,生成会话上下文。
- 发送 Select.rsp,其中包含响应代码(0x0000 表示成功)。
- 状态转换至 Selected。
注意: 被动方在 Not Selected 状态下收到 Select.req 后,如果资源分配失败(如设备 ID 冲突),应发送 Select.rsp 并携带错误代码(如 0x0001),然后保持在 Not Selected 状态,等待主动方重试或断开。
4.2.3 监听与连接请求处理流程图
4.3 超时与重试机制
在 Not Selected 状态下,T3 超时是最关键的异常场景。T3 定时器在发送 Select.req 后启动,如果在规定时间内未收到 Select.rsp,则触发超时处理流程。
4.3.1 T3 超时触发条件
- 主动方: 发送 Select.req 后,T3 定时器到期未收到 Select.rsp。
- 被动方: 被动方不启动 T3 定时器,但如果在 Not Selected 状态下长时间未收到任何消息,可启动连接保活机制(如 Linktest)。
4.3.2 超时恢复策略
当 T3 超时发生时,HSMS 实体应执行以下恢复步骤:
- 重试 Select.req: 重新发送 Select.req,并重置 T3 定时器。重试次数通常为 3 次(可配置)。
- 递增系统字节: 每次重试时,系统字节应递增,以便接收方区分重试消息。
- 连接断开: 如果重试次数耗尽仍未收到响应,则发送 Disconnect.req 并关闭 TCP 连接。
- 日志记录: 记录超时事件、重试次数和最终结果,用于故障诊断。
| 重试次数 | 行为 | T3 超时时间 | 后续动作 |
|---|---|---|---|
| 第 1 次 | 重新发送 Select.req | 45 秒(默认) | 重置 T3 定时器 |
| 第 2 次 | 重新发送 Select.req | 45 秒 | 重置 T3 定时器 |
| 第 3 次 | 重新发送 Select.req | 45 秒 | 若仍超时,断开连接 |
| 超过 3 次 | 发送 Disconnect.req | N/A | 关闭 TCP 连接,进入 Disconnected 状态 |
最佳实践: 建议将 T3 超时重试次数配置为 3 次,超时时间根据网络延迟调整(通常 30-60 秒)。在重试间隔中,可以插入短暂的延迟(如 1-2 秒),避免网络风暴。
4.3.3 超时恢复状态机
4.4 异常场景与处理建议
常见异常: 在 Not Selected 状态下,如果收到重复的 Select.req(系统字节相同),应忽略并保持当前状态,避免重复分配资源。
- 网络分区: 如果 T3 超时后重试仍失败,可能是网络分区导致。建议在重试 3 次后断开连接,并等待上层应用重新建立 TCP 连接。
- 设备 ID 冲突: 被动方在 Not Selected 状态下收到 Select.req 时,如果设备 ID 已被占用,应返回错误代码并保持在 Not Selected 状态,等待主动方重试。
- 半开连接: 如果 TCP 连接处于半开状态(一方已关闭,另一方未感知),Not Selected 状态下的 Select.req 将永远无法收到响应,最终触发 T3 超时并断开连接。
调试建议: 在开发阶段,建议在 Not Selected 状态下打印所有接收到的消息头,包括系统字节和 SType,以便快速定位 Select 流程中的问题。