使用select
模块实现并发处理的思路
- 创建套接字:使用
socket
模块创建一个TCP套接字,并绑定到指定的地址和端口。
- 设置为非阻塞模式:将套接字设置为非阻塞模式,以便
select
模块能够有效地监控其状态。
- 初始化
select
对象:创建一个select
对象,并将服务器套接字添加到读集合中。
- 进入主循环:在主循环中,使用
select
对象监控读集合中的套接字。当有新的连接或数据可读时,select
会返回相应的套接字。
- 处理新连接:如果返回的是服务器套接字,表示有新的客户端连接,接受连接并将新的客户端套接字添加到读集合中。
- 处理客户端数据:如果返回的是客户端套接字,表示该客户端有数据可读,读取数据并进行相应处理,处理完后可选择回显数据或执行其他操作。
- 关闭连接:当客户端关闭连接时,从读集合中移除相应的套接字,并关闭该套接字。
关键代码片段
import socket
import select
def multi_client_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('127.0.0.1', 8888))
server_socket.listen(5)
server_socket.setblocking(False)
inputs = [server_socket]
while inputs:
readable, writable, exceptional = select.select(inputs, [], inputs)
for sock in readable:
if sock is server_socket:
client_socket, client_addr = server_socket.accept()
client_socket.setblocking(False)
inputs.append(client_socket)
else:
try:
data = sock.recv(1024)
if data:
sock.sendall(data)
else:
inputs.remove(sock)
sock.close()
except socket.error:
inputs.remove(sock)
sock.close()
for sock in exceptional:
inputs.remove(sock)
sock.close()
if __name__ == "__main__":
multi_client_server()
使用asyncio
库实现并发处理的思路
- 创建异步函数:定义一个异步函数来处理每个客户端连接,在函数内使用
asyncio
提供的异步I/O操作来读取和写入数据。
- 创建服务器:使用
asyncio.start_server
创建一个TCP服务器,并指定处理客户端连接的异步函数。
- 运行事件循环:获取
asyncio
的事件循环,并将服务器添加到事件循环中运行,事件循环会自动调度处理每个客户端连接的异步任务。
关键代码片段
import asyncio
async def handle_connection(reader, writer):
while True:
data = await reader.read(1024)
if not data:
break
writer.write(data)
await writer.drain()
writer.close()
async def start_server():
server = await asyncio.start_server(handle_connection, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(start_server())