Fix(client): harden TCP heartbeat against half-dead connections
This commit is contained in:
@@ -86,6 +86,27 @@ BOOL SetKeepAliveOptions(int socket, int nKeepAliveSec = 180)
|
||||
}
|
||||
#endif
|
||||
|
||||
// TCP_USER_TIMEOUT (RFC 5482): 未被对端 ACK 的已发数据超过此时间,内核直接把
|
||||
// socket 标记为 ETIMEDOUT,下一次 send/recv 立即报错。
|
||||
//
|
||||
// 为什么 SO_KEEPALIVE 不够:keep-alive 只在连接完全 idle 时才探测,应用层每
|
||||
// 30s 一次心跳让 TCP 永远进不了 idle 态。VM 挂起恢复 / 笔记本合盖唤醒 / NAT
|
||||
// 表项老化等场景下,对端早已关闭连接但本端 send() 仍把字节塞进 SNDBUF 立即
|
||||
// 返回成功——出现 ESTABLISHED + Send-Q 堆积的"半死连接",应用层完全无感,
|
||||
// 默认要等 tcp_retries2 跑完(~15分钟)才报错。
|
||||
//
|
||||
// 选 30s:>= 默认心跳间隔(5-30s),< 服务端 CheckHeartbeat 超时(>=60s)。
|
||||
// Linux 2.6.37+ 支持;macOS / 老内核 无此宏,自动跳过——那条路径上靠应用层
|
||||
// ACK 看门狗(linux/main.cpp 心跳循环)兜底。
|
||||
#ifdef TCP_USER_TIMEOUT
|
||||
unsigned int userTimeoutMs = 30000;
|
||||
if (setsockopt(socket, IPPROTO_TCP, TCP_USER_TIMEOUT,
|
||||
&userTimeoutMs, sizeof(userTimeoutMs)) < 0) {
|
||||
Mprintf("Failed to set TCP_USER_TIMEOUT\n");
|
||||
// 非致命:keep-alive 已设上,应用层还有 ACK 看门狗兜底,继续即可
|
||||
}
|
||||
#endif
|
||||
|
||||
Mprintf("TCP keep-alive settings applied successfully\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user