PythonStudy——多路复用IO select实现
# 服务端代码 import socket import select server = socket.socket() server.bind(("127.0.0.1", 1688)) server.listen(5) # server.setblocking(False) rlist = [server, ] # 将需要检测(是否可读==recv)的socket对象放到该列表中 # accept也是一个读数据操作,默认也会阻塞 也需要让select来检测 # 注意 select最多能检测1024个socket 超出直接报错 这是select自身设计的问题 最终的解决方案epoll wlist = [] # 将需要检测(是否可写==send)的socket对象放到该列表中 # 只要缓冲区不满都可以写 msgs = [("socket", "msg")] # 存储需要发送的数据 等待select 检测后 在进行发送 print("start") while True: readable_list, writeable_list, _ = select.select(rlist, wlist, []) # 会阻塞等到 有一个或多个socket 可以被处理 print("%s个socket可读" % len(readable_list), "%s个socket可写" % len(writeable_list)) """ readable_list 中存储的是已经可以读取数据的socket对象 可能是服务器 可能是客户端 """ # 处理可读列表 for soc in readable_list: if soc == server: # 服务器的处理 client, addr = server.accept() # 将新连接的socket对象 加入到待检测列表中 rlist.append(client) else: try: # 客户端的处理 data = soc.recv(2048) if not data: soc.close() rlist.remove(soc) # 如果对方下线 关闭socket 并且从待检测列表中删除 continue # 不能直接发 因为此时缓冲区可能已经满了 导致send阻塞住, 所以要发送数据前一个先这个socket交给select来检查 # soc.send(data.upper()) if soc not in wlist: wlist.append(soc) # 将要发送的数据先存起来 msgs.append((soc, data)) except ConnectionResetError: soc.close() # 对方下线后 应该从待检测列表中删除 socket rlist.remove(soc) wlist.remove(soc) # 处理可写列表 for soc in writeable_list: # 由于一个客户端可能有多个数据要发送 所以遍历所有客户端 for i in msgs[:]: if i[0] == soc: soc.send(i[1]) # 发送成功 将这个数据从列表中删除 msgs.remove(i) # 数据已经都发给客户端 这个socket还需不需要检测是否可写,必须要删除 wlist.remove(soc) # 否则 只要缓冲区不满 一直处于可写 导致死循环
# 客户端代码 import socket client = socket.socket() client.connect(("127.0.0.1",1688))