在 RT-Thread 4.1.1 和 lwIP 2.1.2 中,处理系统时间计数溢出(sys_now() 返回的 32 位毫秒时间溢出周期约 49.7 天)导致的发送超时问题,代码中已通过 有符号时间差比较 的方式规避。以下是分析和解决方案:
if ((conn->send_timeout != 0) &&
((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout))
{
// 超时处理逻辑
}机制:
sys_now() - time_started 的结果被强制转换为 s32_t(有符号 32 位整数)。当时间差在 [0, 0x7FFFFFFF] 毫秒(约 24.85 天)内时,计算结果正确;超过此范围时,因有符号整数溢出变成负数(<0),但比较条件(>= timeout)自然不成立,不会误判为超时。
合理性:
网络操作的超时时间(conn->send_timeout)通常为秒级(如 30 秒、2 分钟),远小于 24.85 天。因此,在时间溢出周期内:
超时时间过长:
send_timeout 设置 ≥ 24.85 天(极少见),系统时间溢出后,实际未超时但可能被延迟判定。无符号时间差比较(错误示例):
// 错误:若 sys_now() 溢出回绕,将导致超大正数差,错误触发超时
if ((u32_t)(sys_now() - time_started) > timeout) // 不要使用这种方式s32_t 转换 进行有符号比较(如您提供的代码)。连接持续等待问题:
time_started),避免操作跨越多个溢出周期。// 在发送循环中添加检查:若等待超过安全阈值(如 24小时),重置时间
#define SAFE_TIME_INTERVAL (24 * 60 * 60 * 1000) // 24小时(毫秒)
u32_t now = sys_now();
s32_t diff = (s32_t)(now - time_started);
if (diff < 0) { // 发生溢出回绕
// 计算真实无符号差值(规避有符号溢出的负值)
u32_t actual_diff = (0xFFFFFFFFU - time_started) + now + 1;
if (actual_diff > SAFE_TIME_INTERVAL) {
// 重置起始时间,防止永久等待
conn->current_msg->msg.w.time_started = now;
}
}保持当前逻辑:
现有 s32_t 比较在常规场景下安全有效,无需修改核心逻辑。
优化边界问题:
// 设置超时时,限制在安全范围内(如 24 小时)
#define MAX_SEND_TIMEOUT (24 * 60 * 60 * 1000)
if (timeout > MAX_SEND_TIMEOUT) {
timeout = MAX_SEND_TIMEOUT;
}
conn->send_timeout = timeout;系统级改进:
若平台支持,将 sys_now() 升级为 64 位时间戳(需修改 RT-Thread 时钟源),彻底消除溢出问题。
s32_t 比较的设计合理规避了时间溢出误判。rt_tick_get() 扩展为 64 位或使用 rt_tick_t 计算差值)。建议优先在应用层添加超时上限和溢出后的时间重置,确保在长期运行系统中稳定处理网络超时。
举报
更多回帖