长连接空闲 5 分钟后被断开,客户端第 301 秒 send 报 BrokenPipe,服务端日志里没有任何 close 记录,心跳包是 2 字节的 0x0000。碰到这种情况,我一般先确认改动有没有真的生效。

原因不复杂,中间的 NAT 和负载均衡按空闲时间回收会话,2 字节的包可能被当成无效数据丢弃,或者不足以刷新表项。应用层心跳没有对端回应,也算不上真正活跃。

碰到「TCP 心跳保活」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。改完顺手把文档补一句,省得下次自己重新推一遍。

while True:
    sock.sendall(b'PINGPING')
    time.sleep(60)

监控和日志的时间要对上,时区不一致会多绕很大一圈。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

具体做法是,心跳改成带业务头的完整帧;间隔从 300 秒缩到 60 秒;必须等对端回一个 ack 才算成功;连续 3 次没回应再触发重连。

最后用这个标准收尾,改完后连接连续保持 8 小时不断,BrokenPipe 出现 0 次,NAT 表项每 60 秒刷新一次。

作者 9823189