网络编程之I/O复用模型select

来源:互联网 发布:淘宝店掌柜名怎么修改 编辑:程序博客网 时间:2024/05/21 09:13
#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复用模型,可以实现多并发连接请求的同时低资源消耗。

原创粉丝点击