You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线程内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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:27:34