必须继承tornado.websocket.websockethandler并重写open()、on_message()、on_close(),不可用requesthandler替代;write_message()用于发消息,close()用于主动断连,且需自行实现心跳与超时机制保障连接可靠性。

WebSocketHandler 是 Tornado 处理长连接 WebSockets 的核心类,不是靠改配置或加中间件,而是必须继承它并重写生命周期方法。
必须用 WebSocketHandler,不能用 RequestHandler
HTTP 请求走 get()/post(),但 WebSocket 连接建立后不走 HTTP 路由逻辑。如果错误地让 handler 继承 tornado.web.RequestHandler,哪怕路径匹配、握手成功,后续 write_message() 会静默失败,浏览器收不到任何消息,控制台也无报错——这是最常踩的坑。
- WebSocket 连接请求仍以 HTTP 升级(
Upgrade: websocket)发起,但一旦握手完成,协议就切换了 -
RequestHandler没有write_message()方法,调用会抛AttributeError - 必须显式继承
tornado.websocket.WebSocketHandler
open() 和 on_close() 是连接生命周期锚点
这两个方法不带参数,也不返回值,但它们是真正可靠的连接起止信号。别在 open() 里做耗时操作(比如查数据库、发 HTTP 请求),否则会阻塞 IOLoop;也别假设 on_close() 一定被调用——客户端强制断网、浏览器崩溃时可能不会触发。
-
open()适合做轻量初始化:记录连接 ID、存入全局连接池(如clients[conn_id] = self) -
on_close()必须清理资源:从连接池中移除、取消关联的定时任务(如self._ping_loop.stop()) - 不要依赖
on_close()释放关键状态(如锁、文件句柄),应配合心跳超时机制兜底
发送消息只能用 write_message(),且注意类型和异步限制
write_message() 只接受 str、bytes 或可 JSON 序列化的对象(内部自动调用 json.dumps)。传 datetime、自定义类实例会直接报 TypeError;传 None 会变成 JSON null,但某些前端库可能解析失败。
- 发送前务必检查连接状态:
if self.ws_connection is not None and not self.ws_connection.is_closing() - 异步发送需用
await self.write_message(...),但仅当 Tornado ≥ 6.0 且 handler 启用了async def语法才生效;老版本只支持同步调用 - 高频发送时避免连续调用
write_message(),应合并消息或节流,否则可能触发底层缓冲区满导致连接重置
心跳和超时必须自己管,Tornado 不自动保活
Tornado 默认不发 ping/pong,也不检测连接是否僵死。若客户端网络中断而服务端未感知,连接会一直挂在内存里,最终耗尽 fd 或内存。
- 启用 ping:
self.ping()手动触发,配合set_ping_interval(30)和set_ping_timeout(10)控制频率与容忍窗口 - 重写
on_pong()可更新最后活跃时间戳,用于主动踢掉无响应连接 - 别依赖 TCP keepalive:它通常分钟级,远超业务容忍范围;WebSocket 层的心跳才是有效手段
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











