IO多路复用
定义:同时监控多个IO事件,当哪个IO事件准备就绪,就执行哪个IO事件,以此形成可用同时操作多个IO的并发行为,避免一个IO阻塞,造成所有的IO都无法执行
IO准备就绪:是一种IO必然要发生的临界状态
具体方案:
select ---> windows linux unix
poll ---> linux unix
epoll ---> linux unix
三种方案都在select模块中
--------------------select------------------------------------
rs, ws, xs = select(rlist, wlist, xlist[, timeout])
功能:监控IO事件,阻塞等待IO事件发生
参数:rlist 列表 存放我们监听等待处理的IO事件
wlist 列表 存放我们要主动操作的IO事件
xlist 列表 我们要关注出错处理的IO事件
timeout 超时时间
返回值:rs 列表 rlist中准备就绪的IO
ws 列表 wlist中准备就绪的IO
xs 列表 xlist中准备就绪的IO
注意:
* 在处理IO时不要形成死循环,让一个客户端单独占有服务端
* IO多路复兴形成一种可以同时处理多个IO的效果,效率较高
from select import select from socket import * s = socket() #端口的复用,当服务器关闭时,立马释放端口 s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) s.bind(('0.0.0.0',10003)) s.listen(5) rlist=[s] wlist=[] xlist=[] while True: #提交监测我们关注的IO等待IO发生 rs, ws, xs = select(rlist, wlist, xlist) for r in rs: if r is s: c, addr = r.accept() print("Connect from",addr) rlist.append(c) #添加到关注列表 else: data = r.recv(1024) if not data: rlist.remove(r) r.close() else: print(data.decode()) #将客户套接字放入wlist列表 wlist.append(r) for w in ws: w.send(b"Receive your message") wlist.remove(w) for x in xs: if x is s: s.close()
------------------------------poll--------------------------
步骤
1.创建poll对象
p = select.poll()
2.添加注册事件
p.register(s)
也可以移除注册事件
p.unregister(s)
3.阻塞等待IO发生
events = p.poll()
功能:阻塞等待IO发生
返回值:events是一个列表,列表中每一个元素都是一个元组,代表一个发生的IO事件
[(fileno, event),(),()......]
就绪IO的文件描述符 具体就绪的事件
**需要通过文件描述符(fileno)找到对应的IO对象
4.处理具体的IO
事件类别
POLLIN POLLOUT POLLERR POLLHUP POLLPRI
rlist wlist xlist 断开 紧急处理
from socket import * from select import * #创建套接字做为我们关注的IO s = socket() s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) s.bind(('0.0.0.0',10003)) s.listen(5) #创建poll对象 p = poll() #fileno ---> IO对象的字典 fdmap = {s.fileno():s} #注册关注的IO p.register(s,POLLIN | POLLERR) while True: #进行IO监控 events = p.poll() for fd,event in events: if fd == s.fileno(): c,addr = fdmap[fd].accept() print("Connect from", addr) p.register(c,POLLIN | POLLHUP) fdmap[c.fileno()] = c elif event & POLLIN: #利用事件来进行与运算,来判断是否有这事件 data = fdmap[fd].recv(1024) if not data: #客户端退出,从关注事件移除 p.unregister(fd) fdmap[fd].close() del fdmap[fd] else: print(data.decode()) fdmap[fd].send(b"Receive")