Python Asyncio服务器客户端断开后无法停止,添加writer.close()生效的原因?
问题现象与疑问
- 现象:当有客户端连接过(即使客户端已关闭socket),Python Asyncio服务器无法正常关闭;若10秒内无客户端连接则可正常关闭。
- 操作步骤:
- 运行
server.py - 运行
client.py——客户端连接后立即关闭socket
- 运行
- 结果:服务器挂起,无法关闭
- 疑问:在
clientHandler函数中添加writer.close()可解决该问题,请问此操作生效的原因是什么?相关说明文档在哪里?
服务器代码
# server from os import path as ospath import asyncio import socket as Socket import logger as log logger = log.getLogger(fileName=ospath.join('log', 'server.log'), initialize=True) class Client(): def __init__(self, socket:Socket=None, addr:tuple=None) -> None: self.socket = socket self.addr = addr self.connected = False class App(): def __init__(self) -> None: self.quit = False self.clients = [] async def clientHandler(reader, writer): logger.info('client handler starting') async def main(): logger.info("server app starting") app = App() # start socket server ipaddr = Socket.gethostbyname(Socket.gethostname()) port = 32843 logger.info(f'starting socket server ({ipaddr}:{port})') server = await asyncio.start_server(clientHandler, ipaddr, port=32843) logger.info('waiting for client to connect...') await asyncio.sleep(10) logger.info('closing server') server.close() await server.wait_closed() logger.info('server closed') if __name__ == '__main__': asyncio.run(main())
客户端代码
# client import socket dest_ip = socket.gethostbyname(socket.gethostname()) dest_port = 32843 encoder = "utf-8" client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((dest_ip, dest_port)) client_socket.shutdown(socket.SHUT_RDWR) client_socket.close()
解答
生效原因
客户端连接Asyncio服务器后,服务器会为该连接生成StreamReader和StreamWriter实例,它们绑定着底层的socket连接资源。即便客户端主动关闭了自己的socket,服务器端的StreamWriter并不会自动关闭对应的连接,这个未释放的连接会被服务器标记为活跃状态。
当调用server.close()时,服务器会停止接收新连接,但会等待所有已建立的连接处理完毕或关闭后,才会完成整个关闭流程。之前的clientHandler没有处理连接关闭,服务器会一直等待这个未关闭的连接,从而导致挂起无法退出。
添加writer.close()后,会主动关闭服务器端对应的socket连接,释放相关资源。服务器检测到所有连接都已关闭,就能顺利完成await server.wait_closed()的等待,正常退出。
相关文档说明
Python官方文档的**Asyncio 流(Streams)**章节中,明确了StreamWriter.close()的作用:关闭writer对应的传输对象,这会直接关闭底层的socket连接。需要注意的是,close()是非阻塞操作,如果需要等待关闭完成,可以调用await writer.wait_closed()。
另外,关于start_server创建的服务器关闭逻辑,文档提到server.close()仅停止接受新连接,必须等所有已处理连接的传输都关闭后,server.wait_closed()才会执行完成。
内容的提问来源于stack exchange,提问作者iamthebull
相关产品推荐
相关产品推荐

