async/await 不管理 WebSocket 连接状态,真正决定连接存活的是底层协议行为和持续驱动收发逻辑;需主动监听消息或发送心跳,否则空闲超时会被关闭。

async/await 本身不管理 WebSocket 连接状态,它只是让状态相关的异步操作写起来更清晰、更可控。真正决定连接是否存活的,是底层协议行为(如空闲超时、心跳响应)和你是否在 event loop 中持续驱动收发逻辑。
连接建立后必须启动接收循环
WebSocket 不是“连上就自动活着”。即使你只发不收,也得显式监听消息或发送心跳,否则几秒内就会因空闲被关闭(常见错误码 1001 Going Away)。用 async/await 写,就是立即启动一个接收协程:
- 推荐写法:async for message in websocket: —— 自动处理帧迭代与异常退出
- 备选写法:while True: await websocket.recv() —— 需手动捕获 ConnectionClosedError 并 break
- 纯发消息场景:至少加 await websocket.ping() 每 25–30 秒一次,避免服务端单方面断连
状态判断不能只靠 try/catch
await websocket.send() 或 recv() 抛异常,往往已是连接中断的“结果”,而非“原因”。更可靠的判断依据是:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- websocket.closed 属性:True 表示连接已关闭(含正常或异常关闭)
- websocket.open 属性:True 表示处于 OPEN 状态,可安全通信
- 不要依赖“没报错=还连着”——网络抖动可能让下一次 send 突然失败
重连逻辑要退避且解耦
直接在 catch 块里 await connect() 是高危操作:既阻塞当前任务,又容易触发密集重试风暴。正确做法是:
- 捕获 ConnectionClosedError / OSError 后,先检查 websocket.closed 是否为 True
- 用 asyncio.create_task() 启动独立重连协程,不干扰主流程
- 每次重试前 await asyncio.sleep(min(30, 2 ** attempt)),实现指数退避
- 重连成功后,记得清理旧 recv 任务,防止句柄泄漏
send 和 recv 必须同属一个 event loop
所有 WebSocket 操作(send、recv、ping、close)都是协程函数,内部基于 asyncio.StreamReader/Writer。常见误区是用线程池包装它们:
- ❌ loop.run_in_executor(None, websocket.send, data) —— 触发线程争抢、CPU 拉满
- ✅ await websocket.send(data) —— 直接 await,零额外开销
- 真正该进线程池的:JSON 序列化大对象、读写磁盘文件、调用同步 SDK

















