Select与Selectors

多路复用IO的select使用

select基础使用方法

########################################客户端
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('10.11.190.147',8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

client.close()
###########################################服务端
import select
import socket
sk=socket.socket()
sk.bind(('10.11.185.130',8080))
sk.listen(5)
    
while True:
    r,w,e=select.select([sk,],[],[])
    #select时会发生阻塞,直到套接字的状态发生变化
    #如果不想阻塞,可以在最后再添加一个数字参数,如select。select.([sk,],[],[],5)表示非阻塞,每5秒监听一次
    #select会监听第一个列表里的套接字,如果套接字状态变成readable则会把对应的套接字放入r列表中  
    #当socket连接到新的链接,或者conn的收和发生消息时,他们的状态都会变成readable 
    print(r) 
    for obj in r: 
        conn,addr=obj.accept() #如果socket不accept或者conn不recv,则他们会一直处于readable状态 
        data=conn.recv(1024) 
        print(data) 
        conn.send(data.upper())
        

完整客户端/服务端

###########################################服务端
import select
import socket
sk=socket.socket()
sk.bind(('10.11.190.147',8080))
sk.listen(5)
inputs=[sk,]#将需要监听的套接字放进inputs列表里
while True:
    r,w,e=select.select(inputs,[],[])
    for obj in r:
        if obj==sk:
            conn,addr=obj.accept()
            print('connect',conn,'from',addr)
            conn.setblocking(0)     #将套接字设为非阻塞
            inputs.append(conn)     #将套接字放入监听列表中
        else:
            try:
                data=obj.recv(1024)
                if data:
                    print('message',data,'from',obj.getpeername())
                    conn.send(data.upper())
                else: #如果接受为空则关闭链接
                    print('close connect %s',obj.getpeername())
                    obj.close()
                    inputs.remove(obj)  #移除套接字
            except Exception as e:  #如果发生错误,则关闭链接
                print('Error',e)
                print('close connect',obj.getpeername())
                obj.close()
                inputs.remove(obj)  #移除套接字
########################################客户端
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('10.11.190.147',8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

client.close()

除了Select可以实现IO多路复用,还有poll和epoll模块可以实现,它们的不同点是:

Select最多可以监听1024个连接,且管理多个描述符也是进行轮询,根据描述符的状态进行处理,但select在linux,windows,mac上都有

poll解决select的监听个数限制,但是依旧是轮询方式。

epoll解决了轮询问题,可以直接拿到就绪的套接字,但是Windows不支持。

好在我们有selectors模块,帮我们默认选择当前平台下最合适的

Selectors

############################################################服务端
import selectors
import socket
sel=selectors.DefaultSelector()#设置不同平台默认的selectoer
sk=socket.socket()
sk.bind(('10.11.190.147',8080))
sk.setblocking(0)
sk.listen(5)

def accpet(obj,mask):
    print('mask is',mask)
    conn,addr=obj.accept()
    print('connect',conn,'from',addr)
    conn.setblocking(0)
    sel.register(conn,selectors.EVENT_READ,read) #将套接字放入监听列表,并绑定read函数

def read(obj,mask):
    print('mask is',mask)
    try:
        data=obj.recv(1024)
        if data:
            print('message:',data,'from',obj.getpeername())
            message=input('>>:').strip()
            obj.send(message.encode('utf8'))
        else:
            print('close connect:',obj.getpeername())
            sel.unregister(obj)  #将套接字从监听列表中移除,不再监听
            obj.close()
    except Exception as e:
        print(e)
        print('close connect:',obj.getpeername())
        sel.unregister(obj)
        obj.close()

sel.register(sk,selectors.EVENT_READ,accpet)#监听套接字sk,并绑定函数accept
while True:
    events=sel.select() #开始监听
    for obj,mask in events:
        callable=obj.data #获得套接字绑定的函数,如果是sk,则callback=accept
        callable(obj.fileobj,mask)  #执行绑定的函数,obj.fileobj就是拿到的套接字,如果是sk,相当于accpet(sk,mask)
########################################客户端
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('10.11.190.147',8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data.decode('utf-8'))

client.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值