客户端需结合心跳响应与主动探测判断websocket断连:监听onclose/onerror但不依赖它们;发送标准ping控制帧并等待pong响应;发消息前检查readystate;python中用websockets库须手动协程调用ws.ping()而非send文本消息。

客户端怎么知道WebSocket已经断开了
WebSocket连接断开时,onclose 或 onerror 事件会被触发,但**不是所有断开都会走这两个回调**。比如网络突然中断、NAT超时、代理静默丢包,客户端可能收不到任何通知,readyState 却还卡在 OPEN 状态。
真正可靠的判断方式是:结合心跳响应 + 主动探测。
- 监听
onclose和onerror,但不能只依赖它们 - 发送心跳后,必须等待服务端返回
{"type":"pong"}或类似响应;超时未收到即视为异常 - 用
ws.readyState !== WebSocket.OPEN做前置检查,但每次发消息前都应加一层if (ws.readyState === WebSocket.OPEN)防错 - 某些库(如
websockets)提供closed属性或is_closed方法,比查readyState更准
心跳间隔设成10秒,为什么还是断连
10秒是多数美股API的推荐值,但断连仍发生,往往不是间隔本身的问题,而是实现细节没对齐。
常见原因:
- 服务端要求的是 RFC6455 标准
Ping控制帧,但客户端发的是业务层{"type":"ping"}文本消息 —— 有些服务端只响应控制帧,不处理业务 ping -
ping_interval=10设了,但没配ping_timeout(比如设成 3 秒),网络抖动时一次超时就直接断连 - 客户端在主线程阻塞(如长循环、同步 I/O)导致心跳定时器失准,实际间隔远大于 10 秒
- 服务端配置了
pingNotResponseLimit=1,意味着连续漏 1 次心跳就断,而你的重连逻辑没覆盖这个窗口期
验证方法:wscat -c wss://your-api.com/ws 连上后手动发 {"type":"ping"},看是否返回 {"type":"pong"};若无响应,说明服务端根本不认这种格式。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
Python里用websockets库怎么设心跳才生效
websockets 库默认会自动响应 Ping 帧,但**不会自动发送**——它把发送权交给用户。所以 ping_interval 参数在 connect() 中无效,必须自己发。
正确做法是启动一个独立协程,用 ws.send() 发送协议兼容的心跳:
async def send_ping(ws):
while True:
try:
await ws.ping() # ← 发标准 Ping 控制帧,不是 send(json.dumps(...))
except Exception as e:
print("ping failed:", e)
break
await asyncio.sleep(10)
- 用
ws.ping(),不是ws.send('{"type":"ping"}')—— 前者发的是二进制控制帧,后者是文本数据帧 - 确保服务端开启了
enable_ping_pong=True(websocket库老版本默认关,websockets默认开) - 别在
on_message回调里做耗时操作,否则会拖慢整个 event loop,影响心跳协程执行频率
重连时为什么越连越快,最后被限流
高频重连不是因为代码写错了,而是没做退避控制。服务端看到同一 IP 在几秒内反复建连,会主动拒绝后续请求。
关键动作:
- 捕获
ConnectionClosedError或TimeoutError后,先await asyncio.sleep(1)再重试 - 不要只靠
try/except WebSocketConnectionClosedException—— 这类异常常在recv()时才抛,而连接已断的瞬间你根本不知道 - 在
on_close回调里也触发重连,但加一个最小间隔限制(比如至少等 1 秒) - 如果用
run_forever(ping_interval=...),注意它内部的重连是“立即重试”,必须配合ping_timeout和外部兜底逻辑
最易被忽略的一点:重连前检查 ws 实例是否还存在且未关闭。多次重连后旧实例可能残留,ws.close() 失败反而引发新异常。










