select vs epoll
- 连接数量不高但是很活跃select
- 连接数量搞但是不活跃 epoll
select模块的使用:
select会监听socket或者文件描述符的I/O状态变化,并返回变化的socket或者文件描述符对象
select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)
这是Python select方法的原型,接收4个参数
- rlist:list类型,监听其中的socket或者文件描述符是否变为可读状态,返回那些可读的socket或者文件描述符组成的list
- wlist:list类型,监听其中的socket或者文件描述符是否变为可写状态,返回那些可写的socket或者文件描述符组成的list
- xlist:list类型,监听其中的socket或者文件描述符是否出错,返回那些出错的socket或者文件描述符组成的list
- timeout:设置select的超时时间,设置为None代表永远不会超时,即阻塞。
注意:
-
Python的select方法在Windows和Linux环境下的表现是不一样的,Windows下它只支持socket对象,不支持文件描述符(file descriptions),而Linux两者都支持。
-
我们可以通过打印来查看select模块提供的作用,返回的rlist,wlist只会返回有改变的监听对象,如果没有改变的函数,那么整个程序会阻塞住
-
如果我们想要加入新的连接,那么我们只需要把连接对象放进rlist即可,当有数据过来的时候,那么连接就会发生改变(文件描述符),select函数就会帮我们监听到
-
如果我们想发送数据,那么我们可以把conn加入到wlist,因为发送数据需要我们去输出流数据,然后等待select把wlist里面的消息取出来,我们就可以发送数据了
# python select io多路复用测试代码
# 1. 简单的使用select来进行客户端多连接
import select
import socket
import time
# select 把socket放入 select中,然后每当有一个连接过来,把连接conn放入select模型里面去
port = 19834
ip = "127.0.0.1"
ss = socket.socket()
ss.bind((ip, port))
ss.listen(10)
readable_list = [ss]
while 1:
# print('listen again')
rlist, wlist, xlist = select.select(readable_list, [], [],5)
# 如果遍历出来的
print('listen to the readable sockets',rlist)
print('length of the readable sockets',len(rlist))
print('length of the total sockets', len(readable_list))
for i in rlist:
if i is ss:
#如果ss准备就绪,那么说明ss就可以接受连接了,当ss接受到连接
#那么把连接返回readlist
conn,addr = i.accept()
readable_list.append(conn)
注意点 每次我们都需要把send的conn给移除出wlist才行,不然每次conn都会准备好写入,无限的循环
1. 简单的使用select来进行客户端多连接:
import select
import socket
import time
#select 把socket放入 select中,然后每当有一个连接过来,把连接conn放入select模型里面去
port = 19860
ip = "127.0.0.1"
ss = socket.socket()
ss.bind((ip, port))
ss.listen(10)
read_list = [ss]
write_list = []
msg_list = dict()
while 1:
# print('listen again')
rlist, wlist, xlist = select.select(read_list, write_list, [], 5)
for i in rlist:
if i is ss:
# 如果ss准备就绪,那么说明ss就可以接受连接了,当ss接受到连接
# 那么把连接返回readlist
conn, addr = i.accept()
read_list.append(conn)
# 如果不是socket对象,那么就是conn连接对象了,如果是conn连接对象,那么就代表有
# 读入数据的变化,对应recv方法
else:
try:
data = i.recv(1024)
# 如果接受不到数据了 则说明连接已经关闭了
if not data:
print('connecting close')
read_list.remove(i)
break
# 我们去发送数据,但是我们要把conn准备好了再去发送
# 所以首先把数据存在一个dict中msg_list,然后再等他准备好的时候
# 再去发送
msg_list[i] = [data]
if i not in write_list:
write_list.append(i)
except Exception:
read_list.remove(i)
for j in wlist:
# 把对应各自的消息取出来
msg = msg_list[j].pop()
try:
j.send(msg)
# 回复完成后,一定要将outputs中该socket对象移除
write_list.remove(j)
except Exception:
# 如果报错就所以连接或者已经断开了,那么我们就把他移出出去
write_list.remove(j)