4. T3超时模拟:模拟设备不回复Primary Message,Host端触发T3超时重传与Abort流程
T3超时是SECS/GEM协议中Host端等待设备回复Primary Message的关键保护机制。当Host发送一个需要回复的消息(如S1F1、S2F17等)后,会启动T3定时器。若设备因异常(如CPU挂起、通信链路阻塞、应用层死锁)未在T3时间内回复,Host将触发超时重传,并在重传次数耗尽后执行Abort流程。
核心概念:T3超时是Host端消息级超时,区别于T6(设备端回复超时)和T5(连接级心跳超时)。T3超时直接反映设备应用层是否正常处理并回复Host的请求。
4.1 T3超时参数与触发条件
| 参数 | 典型值 | 说明 |
|---|---|---|
| T3定时器 | 45秒(可配置,通常30~120秒) | Host发送Primary Message后等待Reply Message的最大时间 |
| 重传次数 | 3次(可配置,通常2~5次) | T3超时后Host重传Primary Message的最大次数 |
| 重传间隔 | 等于T3值 | 每次重传后重新启动T3定时器 |
| Abort阈值 | 重传次数+1次超时 | 达到阈值后Host终止连接或标记设备不可用 |
触发场景:
- 设备CPU过载,无法及时处理Host请求
- 设备应用层死锁或陷入无限循环
- 设备与Host之间的TCP连接虽然存活,但消息队列阻塞
- 设备回复消息在传输过程中丢失(罕见,但需考虑)
4.2 T3超时重传与Abort流程详解
当Host端检测到T3超时后,按照以下步骤执行重传与Abort流程:
- 超时检测:Host端T3定时器到期,未收到设备的Reply Message。
- 重传计数:Host检查该Primary Message的重传计数器,判断是否达到最大重传次数。
- 重传执行:若未达到阈值,Host重新发送相同的Primary Message,重置T3定时器,重传计数器+1。
- 日志记录:Host记录超时事件,包括消息ID、时间戳、重传次数。
- Abort触发:若重传次数达到阈值,Host执行Abort流程:关闭连接、标记设备状态为“不可用”、通知上层应用。
最佳实践:建议将T3超时重传次数设置为3次,T3值设置为45秒。这样Host在放弃前有约2分15秒的等待时间,既给设备足够的处理时间,又不会让用户等待过久。
4.3 模拟场景:设备不回复Primary Message
以下是一个典型的T3超时模拟场景,使用Python代码演示Host端如何处理设备不回复的情况:
import time
import threading
class T3Timer:
"""T3定时器模拟"""
def __init__(self, timeout=45, max_retries=3):
self.timeout = timeout
self.max_retries = max_retries
self.retry_count = 0
self.timer = None
self.message_id = None
def start(self, message_id):
"""启动T3定时器"""
self.message_id = message_id
self.retry_count = 0
print(f"[Host] 发送 Primary Message {message_id},启动T3定时器 ({self.timeout}s)")
self._start_timer()
def _start_timer(self):
"""内部:启动定时器线程"""
self.timer = threading.Timer(self.timeout, self._on_timeout)
self.timer.start()
def _on_timeout(self):
"""T3超时回调"""
self.retry_count += 1
print(f"[Host] T3超时!Message {self.message_id} 未收到回复 (重传次数: {self.retry_count}/{self.max_retries})")
if self.retry_count <= self.max_retries:
# 重传Primary Message
print(f"[Host] 重传 Primary Message {self.message_id} (第{self.retry_count}次)")
self._start_timer()
else:
# 执行Abort流程
self._abort()
def _abort(self):
"""执行Abort流程"""
print(f"[Host] Abort!Message {self.message_id} 重传次数耗尽")
print("[Host] 关闭TCP连接...")
print("[Host] 标记设备状态为不可用...")
print("[Host] 通知上层应用...")
def cancel(self):
"""取消定时器(收到回复时调用)"""
if self.timer:
self.timer.cancel()
print(f"[Host] 收到设备回复,取消T3定时器")
# 模拟:设备不回复
def simulate_device_no_reply():
host_timer = T3Timer(timeout=5, max_retries=3) # 使用5秒方便演示
host_timer.start("S1F1")
# 设备不回复,等待超时
time.sleep(25) # 5s * (3+1) = 20s,留余量
if __name__ == "__main__":
simulate_device_no_reply()
输出结果:
[Host] 发送 Primary Message S1F1,启动T3定时器 (5s)
[Host] T3超时!Message S1F1 未收到回复 (重传次数: 1/3)
[Host] 重传 Primary Message S1F1 (第1次)
[Host] T3超时!Message S1F1 未收到回复 (重传次数: 2/3)
[Host] 重传 Primary Message S1F1 (第2次)
[Host] T3超时!Message S1F1 未收到回复 (重传次数: 3/3)
[Host] 重传 Primary Message S1F1 (第3次)
[Host] T3超时!Message S1F1 未收到回复 (重传次数: 4/3)
[Host] Abort!Message S1F1 重传次数耗尽
[Host] 关闭TCP连接...
[Host] 标记设备状态为不可用...
[Host] 通知上层应用...
注意:在实际生产环境中,T3超时重传期间,Host应避免发送新的Primary Message给同一设备,防止消息堆积。建议在Abort后等待设备重新连接或手动恢复。
4.4 T3超时与T6超时的对比
| 特性 | T3超时(Host端) | T6超时(设备端) |
|---|---|---|
| 触发方 | Host | 设备 |
| 等待对象 | 设备回复Primary Message | Host回复Secondary Message |
| 典型值 | 45秒 | 45秒 |
| 重传机制 | Host重传Primary Message | 设备重传Secondary Message |
| Abort后果 | Host关闭连接或标记设备不可用 | 设备关闭连接或标记Host不可用 |
| 常见原因 | 设备CPU过载、应用死锁 | Host处理延迟、网络拥塞 |
4.5 避坑指南与最佳实践
- 避免T3值过小:若T3设置过小(如<10秒),设备在处理复杂事务(如晶圆传输、数据采集)时容易误触发超时,导致不必要的重传和Abort。
- 避免T3值过大:若T3设置过大(如>120秒),当设备真正故障时,Host需要等待过长时间才能发现,影响系统响应速度。
- 重传次数不宜过多:超过3次的重传通常无意义,因为设备若在3次重传后仍不回复,大概率是永久性故障。
- Abort后自动重连:建议在Abort后实现自动重连机制,但需设置重连间隔(如30秒)和最大重连次数,防止无限重连。
- 日志记录:每次T3超时和重传都应记录详细日志,包括消息ID、时间戳、重传次数,便于事后分析。
推荐配置:T3 = 45秒,重传次数 = 3次,Abort后等待30秒自动重连,最大重连次数 = 5次。此配置在大多数半导体设备场景中表现良好。