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

2020/01/16 03-IO多路复用库selectors使用
socket和server这样的底层库,只有特别注重效率的时候,才使用,不过推荐用C

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

2020/01/16 03-IO多路复用库selectors使用
一个filetobj在某个时间上,等待某一个data
这个data可以是任意的合法数据

2020/01/16 03-IO多路复用库selectors使用
注册事件会有一个返回值,这个返回值是一个key是SelectKey的类的实例
2020/01/16 03-IO多路复用库selectors使用
监控的事件是读写,recv,send,accept(也是从缓冲区读取),一般一个IO设备能监听的就读和写,
读是1 16进制就是01 2进制就是01 ,写是2 16进制就是 02 2进制就是10

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

2020/01/16 03-IO多路复用库selectors使用
用TCP,注册一个server,准备关注读的事件
下面这么写就阻塞住了

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

现在socket’读事件就是accept,accept调用函数。key.data()即可
2020/01/16 03-IO多路复用库selectors使用
客户端重新连接断开2020/01/16 03-IO多路复用库selectors使用
这种函数其实就是accept
2020/01/16 03-IO多路复用库selectors使用
一旦accept之后该做什么就什么2020/01/16 03-IO多路复用库selectors使用
**一旦读成功,相当于这个函数被调用了
**
2020/01/16 03-IO多路复用库selectors使用
**原来是监控tcp server的 socket的读即server的accept **
2020/01/16 03-IO多路复用库selectors使用
读就绪,可以通过sock拿到一些信息
链接一下

2020/01/16 03-IO多路复用库selectors使用
sock传进来就是这个,用这种方式即可调用
2020/01/16 03-IO多路复用库selectors使用
按照tcp server,就需要拿到与客户端链接的socket
2020/01/16 03-IO多路复用库selectors使用
重新链接一下
2020/01/16 03-IO多路复用库selectors使用
第一个是sock
第二行是conn,本地和远端地址都有
第二行是raddr,远端地址也打印出来了

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

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

2020/01/16 03-IO多路复用库selectors使用2020/01/16 03-IO多路复用库selectors使用
events是一个列表(只放就绪的),列表里是一个个二元组,二元组解开,第一项是key,第二项是mask掩码
key里有4项

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

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

2020/01/16 03-IO多路复用库selectors使用
正好可以测试一下conn的写时间是否会触发select,

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