Python I/O多路复用模块select使用 发表于 2017-12-01 | 阅读次数: 本文字数: 2.6k | 阅读时长 ≈ 2 分钟 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182#Author :ywqimport selectimport socketimport queueserver = socket.socket()server.bind(('localhost',9000))server.listen(1000)server.setblocking(False) #不阻塞msg_dic = {}inputs = [server,]#inputs = [server,conn] #[conn,]#inputs = [server,conn,conn2] #[conn2,]outputs = [] ##outputs = [r1,] #while True: readable ,writeable,exceptional= select.select(inputs, outputs, inputs ) print('Readable:',readable,) print('writable:',writeable) print('exception:',exceptional) print('input:',inputs) for r in readable: if r is server: #代表来了一个新连接 conn,addr = server.accept() print("来了个新连接",conn) inputs.append(conn) #是因为这个新建立的连接还没发数据过来,现在就接收的话程序就报错了 #所以要想实现这个客户端发数据来时server端能知道,就需要让select再监测这个conn msg_dic[conn] = queue.Queue() #初始化一个队列,后面存要返回给这个客户端的数据 #print(msg_dic) else: #conn2 data = r.recv(1024) print("收到数据",data) msg_dic[r].put(data) outputs.append(r) #放入返回的连接队列里 # r.send(data) # print("send done....") for w in writeable: #要返回给客户端的连接列表 data_to_client = msg_dic[w].get() w.send(data_to_client) #返回给客户端源数据 outputs.remove(w) #确保下次循环的时候writeable,不返回这个已经处理完的连接了 for e in exceptional: if e in outputs: outputs.remove(e) inputs.remove(e) del msg_dic[e] print('Readable:',readable,) print('writable:',writeable) print('exception:',exceptional) ''' 1.select.select(rlist,wlist,xlist)运行后生成三个列表,对应变量readable,writeable,exceptional, 三个变量类型也均为list。 2.三个参数:rlist, wlist, xlist,分别代表需要使用select监控的三个装有fd、socket fd的列表, select会监控列表里的fd,一旦传入的参数rlist内有可读的fd对象,则将该对象加入readable变量中。 一旦传入的参数wlist列表中有可写的fd对象,则将该对象加入writeable变量中, 一旦传入的参数xlist列表中有可连接error报错的fd对象,则将该对象加入exceptional变量中。 3.首先要把服务端socket加入inputs内让socket监控它,一旦服务端变为可读状态,即代表有新连接进来了(此时连接还未建立成功) 开始循环,遍历readable、writeable、exceptional三个列表,列表有数据则运行相应指令 与客户端连接建立后,应将客户端socket加入inputs列表,socket监控其是否可读、是否连接报错,此时刚刚建立连接,服务端 还不能直接socket.recv(1024),否则会报错,因为客户端消息还没发过来,要等待下一次循环。 连接建立后,进入下一轮循环,此时需等待客户端传消息过来,传消息过来后,if not is server,则执行else语句, 接收client端传来的消息,并且把client socket加入outputs列表,socket监控其是否可写,并且创建客户端专属队列, 准备开始传消息 4.进入for in writeable的循环,检测发现客户端已经是可写状态了,则开始传送数据。其实writeable也可以监控inputs列表 不用单独创建outputs列表,毕竟所有的连接socket都已经在inputs里边了,但是为了使遍历writeable列表速度更快, 最好把可写列表单独出来,节省资源。 5.总结:select的本质就是为了替程序快速监控fd、socket的I/O状态,以便根据I/O状态快速开始操作,可读可写时则 开始I/O操作,线程去执行其他计算操作。I/O操作时不消耗计算资源。以此交错开来尽量合理化地利用单线程资源。 ''' 一个简单的echo server,使用select I/O复用模型,可以实现多并发连接请求的同时低资源消耗。 赏一瓶快乐回宅水吧~ 打赏 微信支付 支付宝 本文作者: 丨ywq丨 本文链接: https://blog.wqyin.cn/2017/12/01/linux-IO复用模型select.html 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处! -------------本文结束感谢您的阅读-------------