
一次看似简单的“重试两次”,为何第二次永远收不到数据?undefined本文把问题从表面现象一直追到硬件协议层,给出可落地的最终方案。
在 Windows 平台下,我们的代码大致如下(精简后):
// 最外层:业务重试 2 次
for (int i = 0; i < 2; ++i) {
PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);
SendCommData(hComm, szCmd, 30); // 30 字节
if (RecvCommData(hComm, szRecv, 18)) // 想收 18 字节
return SUCCESS;
Sleep(100);
}排查项 | 结果 | 结论 |
|---|---|---|
线路波形 | TX 两次都成功发出 30 字节;RX 第 2 次无任何波形 | 设备未回数据 |
串口缓存 | 每轮都 | 旧数据已清空 |
超时参数 | 单轮 ReadFile 最多 150 ms + 18×100 ms = 1.95 s,足够长 | 不是时间不够 |
波特率 / 时钟 | 已确认正确 | 排除硬件速率问题 |
设备说明书 | “一帧指令一次应答,重复指令不响应” | 根因已找到 |
设备协议本身只支持“单次应答”。
因此:
方案 | 说明 | 代码示例 |
|---|---|---|
A. 一次性收对 | 把单轮超时拉大,确保首轮就能把完整帧收齐。出现错误直接报错,不再重发同一帧。 |
|
B. 协议级重试 | 若必须重试,修改设备固件或协议:带序号/ACK,使设备能区分“重发”。 | 由硬件/固件团队完成 |
C. 上层策略 | 把重试逻辑改为“断电复位→重新上电→再发指令”,让设备重新初始化。 | 电源控制脚或继电器 |
如果硬件无法改动,方案 A 是唯一可行且零成本的落地做法。
COMMTIMEOUTS cto = {0};
cto.ReadIntervalTimeout = 20; // 字节间 20 ms 容错
cto.ReadTotalTimeoutMultiplier = 0; // 不字节累加
cto.ReadTotalTimeoutConstant = 1000; // 整帧 1 s 足够
SetCommTimeouts(hComm, &cto);
// 去掉内部循环重试
BOOL RecvCommData(HANDLE hComm, char* buf, DWORD want)
{
DWORD got = 0;
return ReadFile(hComm, buf, want, &got, NULL) && got == want;
}第二次超时不是 Windows 的问题,而是设备协议“只回一次”。
要么第一轮就保证正确,要么改协议/硬件;否则永远重发无效。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。