第三次汇报学习笔记:多个发送区参与轮发时,需求会迅速从“循环发送”升级到“可控策略”——支持两种模式(定时/等回复)、可配置超时、可配置重发次数,并能只跑一圈。
如果只做“每隔 N ms 轮流发送 1/2/3”,轮发其实很简单:一个定时器 + 一个索引。
但真实使用中经常遇到更复杂的场景:
-
设备回复慢,定时轮发会把请求堆在一起;
-
希望“收到回复再发下一帧”,避免拥塞;
-
还希望加“超时重发”,并设置重发次数;
-
有时还需要“只轮发一圈”。
这些需求本质上都指向同一个结论:轮发不是循环,而是状态机。
1. 轮发的数据模型:先把“状态”列清楚
我把轮发需要的变量拆成几类:
-
m_roundOrder:本轮参与轮发的发送区索引列表(例如 [0,2] 表示只轮发 1 和 3) -
m_roundPos:当前轮发位置 -
m_roundCycle:已经完成的圈数
策略参数
-
m_roundPeriodMs:周期(定时轮发的间隔;等回复轮发里也可作为“发下一帧前的最小间隔”) -
m_roundTimeoutMs:等待回复超时 -
m_roundMaxRetries:超时最大重发次数
状态位(状态机的关键)
-
m_roundRunning:是否正在轮发 -
m_roundWaitReplyMode:是否处于“等回复轮发”模式 -
m_roundWaitingReply:当前帧是否正在等待回复 -
m_roundRetryUsed:当前帧已重发次数 -
m_roundOnlyOnce:是否只轮发一圈
这些变量看起来多,但它们让行为非常可解释:任何异常都能定位到“是哪个状态没收敛”。
2. 两个定时器:一个管“发下一帧”,一个管“等回复超时”
轮发我最终用了两个 QTimer:
-
m_roundTimer:用于定时轮发,或在“收到回复后”延迟发下一帧; -
m_roundReplyTimer:用于等待回复超时(仅在等回复模式启用)。
这样就避免一个定时器承担两种含义导致的混乱。
3. 状态机的核心流程
3.1 start:计算轮发顺序 + 发第一帧
启动时需要:
-
从 3 个发送区里筛选哪些勾选了“参加轮发”;
-
生成
m_roundOrder; -
初始化位置、圈数、重发次数;
-
发送当前帧;
-
根据模式决定进入哪种等待状态:
-
定时轮发:启动
m_roundTimer(period) -
等回复轮发:设置
m_roundWaitingReply=true并启动m_roundReplyTimer(timeout)
-
3.2 advance:位置推进并决定是否结束
推进时(advance)做:
-
m_roundPos++,越界则回到 0,并m_roundCycle++; -
如果
m_roundOnlyOnce且已经完成一圈:停止轮发; -
否则发送新的当前帧,并进入对应等待状态。
3.3 定时轮发:到点就 advance
onRoundTimerTimeout() 只做一件事:advanceRoundAndSend()。
3.4 等回复轮发:收到任何数据即认为“回复到达”
很多协议里回复不一定严格对应某一帧(尤其串口工具不是协议栈),所以我做了一个“工程上够用”的约定:
-
只要收到任何数据,就认为回复到了;
-
然后停止 replyTimer;
-
再用 roundTimer 启动一个最小间隔,间隔到后 advance。
这种策略很朴素,但对“调试助手”足够实用,也能避免 UI 做复杂的帧匹配。
3.5 超时重发:优先重发,超过次数再跳下一帧
当 replyTimer 超时:
-
如果
retryUsed < maxRetries:重发当前帧,retryUsed++; -
否则:提示“进入下一帧”,执行 advance。
并且可以在 statusBar 做即时提示,让用户知道轮发在发生什么。
4. 为什么说这是“状态机”,不是“循环”?
因为“循环”只有一个隐含状态:正在循环; 而“轮发”至少包含这些状态:
-
Running / Stopped
-
Fixed-period / Wait-reply
-
WaitingReply / NotWaitingReply
-
RetryUsed = 0..N
-
OnlyOnce / Forever
只有把状态显式化,才能保证:
-
超时重发不会把索引推进错;
-
收到数据时不会在错误状态触发推进;
-
停止轮发时两个 timer 都能被收敛停止;
-
UI 上的“开始/停止”按钮能正确 enable/disable。
5. 小结
轮发这块我学到的不是“Qt 怎么写定时器”,而是:
-
先建模状态,再写代码;
-
复杂行为拆成多个 timer,各司其职;
-
把推进逻辑封装成
advanceRoundAndSend(),避免散落在多个槽函数里; -
用 statusBar 给用户反馈,调试体验更好。







