实现思路
- 使用异步I/O:选择
asyncio
库来实现异步I/O,以处理高并发连接。asyncio
提供了异步编程的基础设施,允许在单线程内高效处理多个I/O操作。
- 处理客户端连接:使用
asyncio.start_server
创建一个服务器,该服务器会监听指定的地址和端口,每当有新的客户端连接时,创建一个新的任务来处理该客户端的通信。
- 消息接收和发送:在处理客户端连接的任务中,使用异步的
reader
和writer
对象来接收和发送消息。reader
用于读取客户端发送的数据,writer
用于向客户端发送数据。
- 异常处理:在处理客户端连接的任务中,使用
try - except
块捕获可能出现的异常,如连接断开、数据读取错误等,并进行相应的处理,例如关闭连接、记录日志等。
- 资源释放:当客户端连接结束时,确保正确关闭
writer
对象以释放资源,避免资源泄漏。
核心代码片段
import asyncio
async def handle_connection(reader, writer):
try:
while True:
data = await reader.read(1024)
if not data:
break
message = data.decode('utf - 8')
print(f"Received: {message}")
response = f"Message received: {message}"
writer.write(response.encode('utf - 8'))
await writer.drain()
except Exception as e:
print(f"Error: {e}")
finally:
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(handle_connection, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(main())
代码解释
handle_connection
函数:
- 这是处理每个客户端连接的异步函数。
- 使用
while True
循环不断读取客户端发送的数据,await reader.read(1024)
表示异步等待最多读取1024字节的数据。
- 如果没有读取到数据(
if not data:
),说明客户端关闭了连接,跳出循环。
- 接收到数据后,将其解码为字符串并打印,然后构造响应消息并发送回客户端,
await writer.drain()
确保数据被真正发送出去。
- 使用
try - except
捕获可能出现的异常并打印错误信息。
- 在
finally
块中,关闭writer
并等待其关闭,以确保资源释放。
main
函数:
- 使用
asyncio.start_server
创建一个服务器,传入处理连接的函数handle_connection
以及监听的地址和端口。
- 获取服务器套接字的地址并打印。
- 使用
async with server
确保服务器资源的正确管理,await server.serve_forever()
使服务器持续运行,等待客户端连接。
if __name__ == "__main__"
:
- 使用
asyncio.run(main())
来运行异步主函数,启动聊天服务器。