如何用asyncio正确编写自定义Socket服务器?Python3迁移求助
Python3 asyncio Socket服务器无响应冻结问题
原Python2实现代码
我之前在Python2中使用asyncore.dispatcher实现了如下Socket服务器:
import asyncore import socket class Server(asyncore.dispatcher): def __init__(self, host, port, socketMap=None): asyncore.dispatcher.__init__(self, None, socketMap) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((host, port)) self.listen(5) def handle_accept(self): sock, addr = self.accept() handler = Handler(self, sock, self._map) def run(self): while True: asyncore.loop(0.001, True, self._map, 1) self.handle_close() class Handler(asyncore.dispatcher): def __init__(self, server, sock, socketMap): self._server = server asyncore.dispatcher.__init__(self, sock, socketMap) def handle_read(self): buf = self.recv(8192) print(buf) def handle_write(self): sent = self.send("hello")
问题描述
我在Python3中用asyncio重写了代码,但客户端发送数据后服务器无响应且直接冻结,重写的代码如下:
import socket import asyncio class MyAsyncioHandler: def __init__(self, reader, writer): self.reader = reader self.writer = writer async def handle_read(self): data = await self.reader.read(8192) if data: print(f"Received data: {data.decode()}") async def handle_write(self, data): self.writer.write(data) await self.writer.drain() def handle_close(self): print("Connection closed") self.writer.close() async def handle_client(reader, writer): handler = MyAsyncioHandler(reader, writer) while True: await handler.handle_read() data_to_send = b"Response data" await handler.handle_write(data_to_send) async def main(): server = await asyncio.start_server( handle_client, '127.0.0.1', 5000 ) addr = server.sockets[0].getsockname() print(f"Serving on {addr}") async with server: await server.serve_forever() if __name__ == '__main__': asyncio.run(main())
问题原因与修复方案
问题根源
- 无限等待读取:
reader.read(8192)会一直阻塞等待新数据,若客户端发送一次数据后不再发送,服务器会卡在这一步,表现为"冻结"。 - 未处理连接关闭:当客户端主动关闭连接时,
reader.read()会返回空字节,但原代码没有判断该情况,导致循环无限执行无效的读取操作。
修复后的代码
import asyncio class MyAsyncioHandler: def __init__(self, reader, writer): self.reader = reader self.writer = writer async def handle_read(self): data = await self.reader.read(8192) if not data: return None # 返回None标记连接关闭 print(f"Received data: {data.decode()}") return data async def handle_write(self, data): self.writer.write(data) await self.writer.drain() async def handle_close(self): print("Connection closed") self.writer.close() await self.writer.wait_closed() # 确保连接完全关闭 async def handle_client(reader, writer): handler = MyAsyncioHandler(reader, writer) try: while True: data = await handler.handle_read() if data is None: break # 连接关闭,退出循环 # 与原Python2代码保持一致,发送"hello"响应 await handler.handle_write(b"hello") finally: await handler.handle_close() async def main(): server = await asyncio.start_server( handle_client, '127.0.0.1', 5000 ) addr = server.sockets[0].getsockname() print(f"Serving on {addr}") async with server: await server.serve_forever() if __name__ == '__main__': asyncio.run(main())
修复说明
- 在
handle_read中添加空数据判断,返回None标记连接关闭,让循环能正常退出。 - 使用
try/finally块确保无论连接正常关闭还是异常终止,都能正确释放连接资源。 - 将响应内容改为
b"hello",和原Python2代码的逻辑保持一致。 - 新增
await writer.wait_closed(),确保连接彻底关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者test_celery
相关产品推荐
相关产品推荐

