select模块学习
一、select模块
select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。
select目前几乎在所有的平台上支持
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。
#sever端
import socket,select
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen(5)
inp = [sk,]
while 1:
r,w,e = select.select(inp,[],[],5) # timeout超时设置
print('r:',r)
print('w:',w)
print('e:',e)
for obj in r: #sk或是conn有变化时进入循环
if obj == sk: #新的connect会触发sk,没有新connect则不会触发
conn,add = obj.accept()
print('conn:',conn)
inp.append(conn) #将conn加入到监听列表
else: #conn变化
data_byte = obj.recv(1024)
print(str(data_byte,'utf8'))
res = input('回答%s号客户:>>>'%inp.index(obj))
obj.sendall(bytes(res,'utf8'))
print('>>',r) #r中活动的对象
#client
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while 1:
inp = input(">>>")
sk.sendall(bytes(inp,'utf8'))
data = sk.recv(1024)
print(str(data,'utf8'))
二、selectors
#sever
import selectors
import socket
sel = selectors.DefaultSelector()
def accept(sock,mask):
conn,addr = sock.accept()
print('accepted',conn,'from',addr)
conn.setblocking(False)
sel.register(conn,selectors.EVENT_READ,read)
def read(conn,mask):
try:
data = conn.recv(1024)
if not data:
raise Exception
print('echoing',str(data,'utf8'),'to',conn)
data1 = input('回复:')
conn.send(bytes(data1,'utf8'))
except Exception as e:
print('closing',conn)
sel.unregister(conn)
conn.close()
sock = socket.socket()
sock.bind(('localhost',8080))
sock.listen(100)
sock.setblocking(False)
sel.register(sock,selectors.EVENT_READ,accept)
print('server......')
while 1:
events = sel.select() #[sock,conn,conn2]
for key,mask in events:
print('key',key)
print('mask',mask)
callback = key.data #accept/read
print('c')
callback (key.fileobj, mask) #
#client
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while 1:
inp = input(">>>")
sk.sendall(bytes(inp,'utf8'))
data = sk.recv(1024)
print(str(data,'utf8'))