线程内asyncio循环运行的WebSocket建立后立即断开问题排查
问题根因
你怀疑的asyncio与多线程组合冲突并不存在——给WebSocket服务单独开工作线程、在线程内创建独立asyncio事件循环的写法本身是完全合规的。连接立即断开的核心原因有两个:
- 类方法参数错位:
ws_handler是定义在Rotator类内部的实例方法,但你写方法签名时漏了第一个必填的self参数。当你通过self.ws_handler传递方法引用时,Python会自动将当前Rotator实例作为第一个位置参数绑定传入,导致参数对应关系完全错乱:你代码中命名为websocket的形参实际接收到的是Rotator类实例,根本不存在recv()方法,handler一启动就会抛出AttributeError,websockets库捕获到handler运行异常后会直接关闭连接,表现为连接刚建立就断开。你单独测试时把ws_handler写在类外部作为普通函数,不存在实例方法的参数绑定问题,所以运行正常。 - Handler无长连接保持逻辑:就算参数问题修复,你当前的ws_handler逻辑只接收1次消息、回复1次就会执行完毕退出,websockets库在连接对应的handler执行完成后会自动关闭连接,同样会导致连接断开。
修复方案
1. 修正ws_handler定义与逻辑
优先补全实例方法的self参数,同时加入消息循环维持长连接,增加客户端断开的异常捕获:
async def ws_handler(self, websocket, path): try: # 异步迭代持续接收客户端消息,维持长连接 async for data in websocket: reply = f"Data recieved as: {data}!" await websocket.send(reply) except websockets.exceptions.ConnectionClosed: # 客户端主动断开时的清理逻辑,可按需添加日志 pass
如果ws_handler不需要访问Rotator实例的任何属性、方法,也可以给方法加@staticmethod装饰器,此时不需要加self参数:
@staticmethod async def ws_handler(websocket, path): try: async for data in websocket: reply = f"Data recieved as: {data}!" await websocket.send(reply) except websockets.exceptions.ConnectionClosed: pass
2. 优化Socket线程的事件循环写法(可选,推荐)
显式将线程内创建的事件循环传给websockets.serve,避免不同Python版本、不同websockets版本下隐式获取事件循环的兼容问题:
def _SocketThread(self): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) start_server = websockets.serve( self.ws_handler, host=str(self.DHCPIP), port=8000, loop=loop ) loop.run_until_complete(start_server) loop.run_forever()
改完后WebSocket连接就可以正常保持,不会出现建连即断的问题。
内容的提问来源于stack exchange,提问作者Hristo Kolev
相关产品推荐
相关产品推荐

