Python I/O多路复用模块select使用

#Author :ywq
import select
import socket
import queue


server = 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复用模型,可以实现多并发连接请求的同时低资源消耗。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值