本文将帮助开发者理解和解决在使用 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