解决 WebSocket 连接中 ConnectionClosedOK 错误

解决 WebSocket 连接中 ConnectionClosedOK 错误

本文将帮助开发者理解和解决在使用 python websockets 库时遇到的 ConnectionClosedOK 错误。该错误通常发生在客户端发送一次请求后,服务端关闭连接的情况下。本文将介绍两种解决方案:第一种方案,客户端在每次请求时建立新的 WebSocket 连接,适用于客户端请求次数较少的情况。第二种方案,服务端通过循环保持 WebSocket 连接的活跃状态,允许客户端多次请求,并探讨了如何优雅地关闭连接。

在 websockets 库中,服务端在处理完一次客户端请求后默认会关闭连接,这会导致客户端在尝试后续请求时遇到 ConnectionClosedOK 错误。要解决这个问题,我们需要根据实际需求选择合适的方案。

方案一:客户端每次请求建立新连接

这种方案适用于客户端请求次数较少,或者每次请求都需要独立连接的场景。核心思想是移除客户端代码中的 while 循环,利用 async for 循环的特性,每次迭代都建立一个新的连接。

修改后的客户端代码如下:

import time import json import asyncio import websockets import nest_asyncio nest_asyncio.apply()   async def get_data(websocket, key):     order = {'key': key}     json_data = json.dumps(order)     await websocket.send(json_data)     res = await asyncio.wait_for(websocket.recv(), timeout=10)     res = json.loads(res)     return res   async def main():     i = 0     uri = "ws://localhost:8765"     async for websocket in websockets.connect(uri, timeout=15, ping_timeout=None, ping_interval=None):         if i < 10:             i = i + 1             print(f'counter {i}')             res = await get_data(websocket, 'key')             print(f"res: {res}")             time.sleep(3)  # slow down for tests         else:             break      print('main exit')   if __name__ == "__main__":     asyncio.get_event_loop().run_until_complete(main())

注意事项:

  • 当退出 async for websocket 循环时,可能会抛出 GeneratorExit 异常。可以使用 try/except 块捕获该异常,进行必要的清理工作。

方案二:服务端保持连接活跃

如果需要客户端和服务端保持长时间的连接,以便进行多次数据交换,则需要在服务端代码中添加一个循环,使得 handle_request 函数持续运行。

修改后的服务端代码如下:

import json import asyncio import websockets import nest_asyncio nest_asyncio.apply()   async def handle_request(websocket):     while True:         try:             message = await websocket.recv()             data = json.loads(message)              order = {'key': data['key'], 'val1': 1.0, 'val2': 2.0}             json_data = json.dumps(order)             await websocket.send(json_data)         except websockets.ConnectionClosedOK:             break     print("handle_request")   async def main():     async with websockets.serve(handle_request, "localhost", 8765, ping_interval=None):         print('world running...')         await asyncio.Future()  # run forever     print('world done')   if __name__ == "__main__":     asyncio.run(main())

代码解释:

  • while True 循环使得 handle_request 函数可以持续接收和处理客户端的请求。
  • try/except 块用于捕获 websockets.ConnectionClosedOK 异常,当客户端关闭连接时,服务端会退出循环,避免程序崩溃。

注意事项:

  • 客户端也需要相应的机制来退出 async for websocket 循环,例如设置最大请求次数或接收到特定的关闭消息。
  • 在长时间保持连接的情况下,需要考虑心跳机制,定期发送 ping 消息,以确保连接的有效性。

总结

ConnectionClosedOK 错误通常是由于客户端和服务端连接管理方式不匹配导致的。通过选择合适的解决方案,并结合 try/except 块进行异常处理,可以有效地解决该问题,构建稳定可靠的 WebSocket 应用。在实际开发中,应根据具体的业务需求和场景,选择最合适的连接管理策略。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享