Python asyncio单事件循环下一个服务遇ConnectionResetError导致另一服务关闭
问题根因
- 你的
handle_client连接处理回调没有捕获客户端强制断开抛出的ConnectionResetError异常。asyncio事件循环中任意任务抛出未捕获异常时,默认会终止整个事件循环,因此运行在同一循环上的两个服务会同时停止。 - 目前HTTP服务的启动逻辑存在不规范问题,虽未直接触发本次故障,但长期运行存在资源回收风险。
解决方案
1. 补全handle_client的异常捕获逻辑
在连接处理函数外层添加全局异常拦截,避免连接异常上浮到事件循环,参考实现:
import asyncio async def handle_client(reader, writer): peername = writer.get_extra_info('peername') try: # 原有业务处理逻辑全部移入try块 while True: data = await reader.readexactly(msg_headers.X_MSG_TCP_DATA_BUF_SIZE) # 你的业务处理代码 # 捕获所有客户端断开相关的常见异常 except (ConnectionResetError, asyncio.IncompleteReadError, BrokenPipeError, ConnectionAbortedError): print(f"客户端{peername}已断开连接") # 兜底捕获其他异常,避免漏网之鱼导致服务崩溃 except Exception as e: print(f"客户端{peername}处理异常:{repr(e)}") # 统一释放连接资源 finally: try: writer.close() await writer.wait_closed() except: pass
2. 优化服务启动逻辑(可选,提升稳定性)
你当前的HTTP服务启动后没有显式的保活逻辑,仅靠TCP服务的serve_forever()阻塞维持运行,更规范的写法是将两个服务的运行任务统一托管给事件循环,还可以通过return_exceptions参数做第二层保险:
async def main(port: int, addr: str, verbose: int, restapiport: int): # 初始化并启动HTTP服务 runner = aiohttp.AppRunner(await init_app()) await runner.setup() site = web.TCPSite(runner, str(addr), restapiport) await site.start() print(f'Serving RPC on {addr}:{restapiport} ...') # 初始化并启动TCP服务 server = await asyncio.start_server(handle_client, str(addr), port) service_addr = server.sockets[0].getsockname() print(f'Serving MBE on {service_addr} CSID={os.environ["CSID"]}') # 统一托管服务运行任务 async with server: await asyncio.gather( server.serve_forever(), return_exceptions=True )
return_exceptions=True配置会将任务异常作为返回值返回,不会终止其他并行任务,进一步提升服务可用性。
内容的提问来源于stack exchange,提问作者Yaron
相关产品推荐
相关产品推荐

