网络 TCPWebSocketMQTT

TCP 心跳、WebSocket Ping、MQTT Keep-Alive 有什么区别

长连接三兄弟都叫"心跳",但它们解决的是三个不同层的问题。排查线上断连问题的时候,先分清是哪一层的保活失效了。

TCP Keep-Alive:操作系统级的探活,默认 7200 秒才开始第一次探测,基本等于摆设,要用必须 setsockopt 改三个参数。它回答的问题是"这条 TCP 连接对端还活着吗"。NAT 网关通常 300 秒就回收无流量的映射表项,所以纯靠 TCP Keep-Alive 穿 NAT 基本没戏。

WebSocket Ping/Pong:协议层的控制帧,RFC 6455 定义,Ping 带的 payload 会原样在 Pong 里带回来。浏览器 JS 里不能主动发 Ping(浏览器自动回 Pong),所以网页端的心跳一般是业务层自己造一个 {"type":"ping"} 消息。它回答的问题是"这条路现在通不通",探测粒度最细、延迟最低。

MQTT Keep-Alive:客户端在 CONNECT 里承诺"我最多 N 秒发点动静",1.5 倍 N 秒内没收到任何报文,服务端就断开。它回答的问题是"这个客户端还在线吗",本质是在线状态的仲裁机制,而不是链路探测。

三者叠加时的经典事故:应用层 WebSocket 心跳 30 秒一次,NAT 超时配了 240 秒,MQTT Keep-Alive 设了 60 秒——看起来全都在保活,但 MQTT 代理压根看不到 WebSocket 层的 ping 帧(被 WS 协议吃掉了),于是在线状态莫名其妙掉线。正确做法是把保活的责任收敛到一层,其他层要么关掉要么对齐节奏。

一句话总结:探链路用 WebSocket Ping,穿 NAT 靠应用层心跳,管在线状态用 MQTT Keep-Alive。别让三层各跑各的。