如何将Python select读列表中的套接字传入自定义recvAll函数?
使用Python select结合recvAll处理异步套接字读取
嘿,我来帮你梳理下怎么把select返回的可读套接字传给你的recvAll函数,其实核心思路就是利用select筛选出当前有数据的套接字,再逐个丢给你的函数处理就行。下面是具体的实现步骤和代码示例:
核心逻辑拆解
- 先把你要监听的两个套接字放到一个可读列表里
- 调用
select.select()获取当前真正有数据可读的套接字集合 - 遍历这个集合,把每个套接字传入
recvAll读取完整数据
完整代码示例(兼容Python3)
import select import socket from errno import errorcode def recvAll(sock): buffer = b'' # 注意:Python3里recv返回bytes,用bytes存储更稳妥 data_chunks = [] try: while True: chunk = sock.recv(8192) if not chunk: # 对方关闭套接字,停止读取 break data_chunks.append(chunk) # 如果你是基于应用层协议判断是否收完(比如有长度头),可以在这里加判断逻辑 # 不过你的需求是读取全部数据直到套接字关闭,所以保持循环即可 except OSError as e: # 替换Python2的error异常,10035是非阻塞套接字的正常"暂时无数据"错误 if e.errno != 10035: print(f"套接字错误:{errorcode[e.errno]} - {e.strerror}") # 这里可以根据业务需求添加错误处理,比如断开连接等 return b''.join(data_chunks) # 初始化两个要监听的套接字(假设已经完成连接/监听) sock_a = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_a.connect(('target-host-1.com', 80)) sock_b = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock_b.connect(('target-host-2.com', 80)) # 维护要监听的可读套接字列表 read_list = [sock_a, sock_b] while True: # 调用select,阻塞直到有套接字可读、可写或异常 readable, _, exceptional = select.select(read_list, [], read_list) # 处理可读的套接字 for sock in readable: full_data = recvAll(sock) if full_data: print(f"从 {sock.getpeername()} 收到完整数据:\n{full_data}") else: # 收到空数据说明套接字已关闭,从监听列表移除并关闭 print(f"套接字 {sock.getpeername()} 已断开连接") read_list.remove(sock) sock.close() # 如果没有需要监听的套接字了,退出循环 if not read_list: break # 处理异常套接字(可选) for sock in exceptional: print(f"套接字 {sock.getpeername()} 发生异常") read_list.remove(sock) sock.close()
几个关键注意点
- 字节类型适配:Python3中
sock.recv()返回的是bytes对象,不是字符串,所以recvAll里的缓冲区要改成bytes类型,避免编码报错 - 异常处理更新:Python2的
error异常在Python3中统一为OSError,需要调整捕获方式;而10035错误是非阻塞套接字的正常情况,表示当前没有更多数据可读,所以可以忽略这个异常 - 套接字生命周期管理:当
recvAll返回空时,说明对方已经关闭了套接字,一定要把它从监听列表里移除并关闭,不然select会一直触发这个套接字的可读事件 - 协议适配:如果你的应用层协议有固定的报文格式(比如带长度前缀),可以在
recvAll里加判断逻辑,不用等到套接字关闭就停止读取,这样效率更高
内容的提问来源于stack exchange,提问作者nb12345
相关产品推荐
相关产品推荐

