2020/01/16 03-IO多路复用库selectors使用

在这里插入图片描述
socket和server这样的底层库,只有特别注重效率的时候,才使用,不过推荐用C

**主要是select和poll是线性遍历的,在内存中,消息需要大量的复制,使用这样的方式,在soskcet不断接受数据,大量数据需要从用户控件到达内核空间,来回浪费大量系统资源,最好的是选择当前操作系统最强的一种IO模式来编程,比如Linux的EPOLL
**
在这里插入图片描述
提供了一个DefaultSelector,返回当前操作系统最有效的select模型,初始化之后,注册想关注的IO是什么,下面就可以通过 回调方式获取这个IO的数据在这里插入图片描述
这是源码里写的
在这里插入图片描述
创建出select对象,关注文件对象,
需要注册register(fileobj,events,data=None)
fileobj文件对象,例如socket对象
event,监控对象产生什么事件
data 可选的与此文件对象相关联的不透明数据,也就是一旦这个对象所关注的事件,一旦满足了,产生一个特别的东西出来,这里面就带着data

在这里插入图片描述
一个filetobj在某个时间上,等待某一个data
这个data可以是任意的合法数据

在这里插入图片描述
注册事件会有一个返回值,这个返回值是一个key是SelectKey的类的实例
在这里插入图片描述
监控的事件是读写,recv,send,accept(也是从缓冲区读取),一般一个IO设备能监听的就读和写,
读是1 16进制就是01 2进制就是01 ,写是2 16进制就是 02 2进制就是10

读缓冲已经有数据,可以读,写缓冲已经好了,可以写
在这里插入图片描述
内核中数据准备好了数据搬到用户空间
在这里插入图片描述在这里插入图片描述
可以调用recv,获取数据
在这里插入图片描述
可以写数据,用户空间数据可以复制到内核空间
在这里插入图片描述
这个类有4个属性
fileobj 注册的文件对象
fd 每打开的文件对象,和socket都有一个fd,j就存在这个register成功后返回的key里
event 要关注哪些事件
data就是在注册时,注册的data

在这里插入图片描述
用TCP,注册一个server,准备关注读的事件
下面这么写就阻塞住了

在这里插入图片描述
select是阻塞行为,如果注册的socket确实等到了某些数据,就不阻塞了,会返回一个events的对象
在这里插入图片描述
selectkey包含的就是自己的字符串表达形式
在这里插入图片描述
fd就是socket fd =244
在这里插入图片描述
event=1是读,2是写
在这里插入图片描述
链接一下
在这里插入图片描述
程序就退出了
在这里插入图片描述
events返回的就是key,后面+1,是个列表,event是两项,返回的是一个kv对在这里插入图片描述
1其实就是对应read
在这里插入图片描述
1向左移0位还是1,1向左移1位,就是2
在这里插入图片描述
刚才如果不链接select,一直等下去在这里插入图片描述
accept可以没有,accept对这个socket来讲,就是读取的意思在这里插入图片描述
这里指定监控的事件
在这里插入图片描述
events返回的是一个列表,写成这样,链接在这里插入图片描述
type告诉你是一个selectkey在这里插入图片描述
mask其实返回的是监听东西的值,ip地址的mask掩码是来做位与的,key.data有4个属性在这里插入图片描述
链接一下
在这里插入图片描述
key.data就是送过来的值在这里插入图片描述
监控这个server的socket,监控的读事件,如果产生了,select就不阻塞了,返回一个events,遍历所有events,现在监控的就一个,可以这么写,监控多的就不可以这么写了

现在socket’读事件就是accept,accept调用函数。key.data()即可
在这里插入图片描述
客户端重新连接断开在这里插入图片描述
这种函数其实就是accept
在这里插入图片描述
一旦accept之后该做什么就什么在这里插入图片描述
**一旦读成功,相当于这个函数被调用了
**
在这里插入图片描述
**原来是监控tcp server的 socket的读即server的accept **
在这里插入图片描述
读就绪,可以通过sock拿到一些信息
链接一下

在这里插入图片描述
sock传进来就是这个,用这种方式即可调用
在这里插入图片描述
按照tcp server,就需要拿到与客户端链接的socket
在这里插入图片描述
重新链接一下
在这里插入图片描述
第一个是sock
第二行是conn,本地和远端地址都有
第二行是raddr,远端地址也打印出来了

在这里插入图片描述
有了conn,知道对端地址,socket可以send数据出去
在这里插入图片描述
链接一下,hello client就发送过来 了
在这里插入图片描述
首先把IO等待读写交给select,epoll,首先需要建立select对象,有了select对象之后要准备socket,
在这里插入图片描述
socket需要自己该绑定绑定,该listen listen在这里插入图片描述
accept是读,读就绪,交给select正好
server socket做好了,就差读写的事情,准备监控读,
因为IO多路复用,为每一个监控的对象,加了一个数据,data,配一个数据单独为它处理
这个register注册之后分配一个key,selectkey

在这里插入图片描述
selectkey有4个属性,fileobj,fd(需要监控的文件对象的target,文件描述符),events(监控什么消息),data
select方法是会阻塞的,它要等待,你让我监控的所有socket的所有事件就绪
一旦有一个或者多个就绪了,放在一个容器里events,
每一项都是监控的socket的key,就绪之后得到的值mask,读就绪的mask=1,写mask=2,
读写都就绪了,就是2进制的11,10进制的3
用mask就可以与,不重复

在这里插入图片描述在这里插入图片描述
events是一个列表(只放就绪的),列表里是一个个二元组,二元组解开,第一项是key,第二项是mask掩码
key里有4项

在这里插入图片描述
注册只要一次就够了,处理完再看,再次调select,就循环起来
在这里插入图片描述
conn也是socket,可以监控起来
在这里插入图片描述
这句话往上搬,新的socket创建出来后,就需要关注,每accept成功一次,就会创建一个新的socket,(select有数组一样的东西,把所有socket的,一个个遍历)
每一次进来conn都不同,register注册监控read即可,现在就有key了
在这里插入图片描述
每创建一个客户端和server端单独的new socket之间通信的socket,关注起来这个socket,要关注它的recv
在这里插入图片描述
数据从远端发送到你的内核的数据缓冲区,数据缓冲区好了通知你recv,(刚才的accept就是,准备好 了,通知你accept一下)
select提醒数据到内核空间了,由你自己把数据从内核缓冲区读取到自己的进程的缓冲区中

key.data如果是recv,就不支持传参,需要改成这样在这里插入图片描述
**但凡有人链接,都会不阻塞,然后调用这个函数 **
在这里插入图片描述
调用accept函数,相当于循环在这里插入图片描述
recv,能读,也是下面通知,这样select就进行了多路监控,到底读不读,是下面select通知的,数据在内核缓冲区了,可以直接从内核空间读到用户空间的进程里在这里插入图片描述
把数据接收到,data,可以自己打印data
decode是把bytes转换成字符串
encode把字符串转换成bytes
现在循环都交给select来处理

在这里插入图片描述
正好可以测试一下conn的写时间是否会触发select,

在这里插入图片描述
链接进来会调用accept这个方法,注册好之后,紧接着用socket来send,写事件
在这里插入图片描述
写事件看看能否触发recv
在这里插入图片描述
连接一下
在这里插入图片描述
在这里插入图片描述
所以不是它监听的事件就不理你在这里插入图片描述
现在试试单聊能不能触发recv
在这里插入图片描述
触发了没有问题
在这里插入图片描述
有了这个例子基础,就可以去写群聊了在这里插入图片描述
通过select关注,你所让关注的注册的某些文件对象,关注这个文件对象的哪些事件,select就帮助你对你所关注的socket IO进行监控,当IO上 的某些监控的事件产生了,select就会停止阻塞,会返回一个集合,内部返回当下产生事件的key,mask,通过key和mask可以操作一些函数在这里插入图片描述在这里插入图片描述