Python 3.6.5 Asyncio端口阻塞问题:无连接时无法终止进程求助
问题分析与修复方案
我来帮你拆解这个问题:
当没有活跃TCP连接时,按下Ctrl+C进程无响应,核心原因是事件循环的清理流程不完整。具体来说:
- 无活跃连接时,
loop.run_forever()会一直阻塞在监听状态,收到KeyboardInterrupt后,原代码直接执行server.close(),随后调用loop.run_until_complete(server.wait_closed())。但此时事件循环没有被正确终止,导致server.wait_closed()的完成信号无法被事件循环处理,进程会一直卡在这一步。 - 另外,原
handle_echo函数中关闭客户端socket时,只调用了writer.close(),没有等待连接完全关闭(await writer.wait_closed()),这虽然不是当前问题的直接诱因,但会导致连接资源无法及时释放,影响服务器健壮性。
修复后的完整代码
import asyncio async def handle_echo(reader, writer): data = await reader.read(100) message = data.decode() while message != "-": addr = writer.get_extra_info('peername') print("Received %r from %r" % (message, addr)) print("Send: %r" % message) writer.write(data) await writer.drain() data = await reader.read(100) message = data.decode() print("Close the client socket") writer.close() await writer.wait_closed() # 等待客户端连接完全关闭 loop = asyncio.get_event_loop() coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop) server = loop.run_until_complete(coro) print('Serving on {}'.format(server.sockets[0].getsockname())) try: loop.run_forever() except KeyboardInterrupt: print("\nShutting down server...") loop.stop() # 先停止事件循环,确保后续清理任务能被处理 # 关闭服务器并等待所有资源释放 server.close() loop.run_until_complete(server.wait_closed()) # 清理异步生成器(Python 3.6+ 推荐操作) loop.run_until_complete(loop.shutdown_asyncgens()) loop.close()
关键修复点说明
- 添加
loop.stop():捕获KeyboardInterrupt后先调用loop.stop(),终止loop.run_forever()的阻塞状态,让事件循环可以切换到处理后续的服务器关闭任务。 - 等待客户端连接关闭:在
handle_echo中添加await writer.wait_closed(),确保客户端socket完全关闭后再结束协程,避免连接资源泄漏。 - 清理异步生成器:调用
loop.shutdown_asyncgens(),这是Python 3.6及以上版本的推荐操作,用于清理所有异步生成器,防止潜在的资源泄漏。
修改后,无论是否有活跃连接,按下Ctrl+C都能正常终止进程,完成服务器的优雅关闭。
内容的提问来源于stack exchange,提问作者Jacob Chrzanowski
相关产品推荐
相关产品推荐

