WebSocket连接存活靠协议级pong响应和业务层消息双重判断;仅依赖readyState不可靠,必须结合ping/pong帧交互与应用消息时间戳验证,二者缺一不可。

心跳包不是可选功能,而是连接存活的底线保障;不设或乱设 ping_interval 和 ping_timeout,连接大概率会在 30–120 秒内被中间设备或服务端静默断开。
WebSocket 连接存活靠什么判断?
不是靠 ws.readyState === WebSocket.OPEN,这个值在真实断连后可能仍为 OPEN 长达数秒甚至更久。真正可靠的判断依据只有两个:
- 客户端是否成功收到服务端对
ping的pong响应(底层协议级) - 应用层是否在约定时间内收到了业务消息(如行情 tick、确认 ack)
前者由 WebSocket 协议栈自动处理(如 Python websockets 库),后者需你自己监听 onmessage 并维护时间戳。两者缺一不可——只依赖协议心跳,可能漏掉业务层卡死;只依赖业务消息,可能被防火墙提前 kill。
ping_interval 和 ping_timeout 怎么配才不翻车?
这两个参数必须满足:ping_interval ping_timeout
-
ping_interval=60+ping_timeout=60:超时等于间隔,一旦网络抖动,pong稍晚几秒就触发断连 -
ping_interval=30+ping_timeout=20:逻辑矛盾,还没等响应就判定超时 - 完全不设(用默认值):Python
websockets默认ping_interval=20、ping_timeout=20,对美股 API 来说太激进,部分服务端会拒绝这种高频探测
实测推荐组合(针对美股实时行情类 API):
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 保守稳定型:
ping_interval=10,ping_timeout=5(适合高可靠性要求,容忍略高 CPU) - 平衡通用型:
ping_interval=15,ping_timeout=8(适配多数服务端策略,网络波动下容错较好) - 轻量省资源型:
ping_interval=25,ping_timeout=12(需确认服务端文档允许 ≥20 秒空闲)
为什么自己发 {"type":"ping"} 不如用原生 ping?
手动发送 JSON 心跳是伪心跳,存在三个硬伤:
- 服务端不一定解析或回应它——很多美股 API(如 AllTick、Polygon)只认标准 WebSocket
PING帧,对应用层字符串直接忽略 - 无法触发协议级
pong自动响应,你得自己写onmessage解析并计时,容易漏判 - 增加单次通信体积和序列化开销,高频下影响吞吐(尤其订阅上百只股票时)
正确做法是交由库处理:Python websockets 的 ping_interval 会自动发二进制 PING 帧,并在 ping_timeout 内监听底层 PONG;JavaScript 的 ws.ping() 同理。自己封装的 JSON 心跳,仅作业务保活补充,不能替代协议心跳。
最容易被忽略的断连诱因:服务端不回 pong
即使你把 ping_interval 设得很小,如果服务端压根不响应 PONG(比如某些旧版 Node.js ws 库未启用 clientTracking: true),客户端会在第一个超时后立即关闭连接,且不会报错——日志里只显示 Connection closed,没有原因。
验证方法很简单:用 tcpdump 或 Wireshark 抓包,过滤 WebSocket 流,看是否有 PING → PONG 往返。没有?那问题不在你的客户端配置,而在服务端是否真正启用了心跳支持。这时候调大 ping_timeout 没用,得换服务端或联系 API 提供方确认。

















