I/O多路复用(I/O multiplexing),可以简要理解为:多条socket复用一个I/O管理线程;
存在意义:用来监听和管理socket连接是否有变化。
早期管理方法:多进程并发模型(每一个socket,分配一个独立的进程来管理)
近期管理方法:I/O多路复用(单个线程通过跟踪记录每个socket的状态来管理多个socket连接)
详细解释可以点击此处
实现I/O多路复用主要有三种方法:select、poll、epoll(按照出现的先后顺序)
以下简要讲一下Python中的三种方法:
内部的方法就是一个类似for循环的处理,其在不断的进行检查socket对象是否改变,但是受限于监听的1024连接上限
select有以下缺点:
1、有1024个连接的上限;
2、会修改传入的参数数组;
3、如果任何一个socket(I/O stream)出现了数据变化,select 仅仅会返回,但是并不会告诉管理端是那个sock上有变化,因此就得for循环去挨个查,socket数量少时还可以,要是几W条,那就太浪费资源了;
去掉了select的1024上限,不再修改参数数组,但本质依然是类似for循环的处理;
内部监听机制改变了,以前的select、poll是server去循环的挨个检查监听的socket连接,而epoll则是socket状态一旦改变,就会主动给epoll-server通知一下;
熟悉zabbix收集消息的方式的同学,可以理解为zabbix就是socket管理程序select、poll就是其被动机制;epoll为主动机制;
用途:可以用来监听 I/O stream 即:既监听socket,也监听 数据读写,但是不支持文件处理类的监听
下面分享一下python中select的使用方法:
#!/usr/bin/env python
# -- coding = 'utf-8' --
# Author Allen Lee
# Python Version 3.5.1
# OS Windows 7
import socket,select
server = socket.socket()
server.bind(('127.0.0.1',8808,))
server.listen(5)
inputs = [server,]
outputs = []
messages = {}
xlist = []
while True:
"""
select的 第一个参数为监听有数据变化的socket对象,并放到rlist中;
第二个参数为只要写入wlist,不论是否变化,都会被监听;
第三个参数为,如果某个socket报错了就计入xlist;
最后一个参数为间隔时间
"""
rlist,wlist,xlist = select.select(inputs,outputs,xlist,1)
print(len(inputs),len(rlist),len(outputs),len(wlist))
for i in rlist:
if i == server:
conn,addr = i.accept()
inputs.append(conn)
conn.sendall(bytes('hello',encoding='utf-8'))
else:
print('===============')
try:
res_data = conn.recv(1024)
if not res_data:
raise Exception("断开连接")
else:
outputs.append(i)
messages[r].append(res_data)
except Exception as e:
inputs.remove(r)
del messages[i]
for w in wlist:
msg = messages[w].pop()
resp = msg + bytes('response',encoding='utf-8')
w.sendall(resp)
outputs.remove(w)
#!/usr/bin/env python
# -- coding = 'utf-8' --
# Author Allen Lee
# Python Version 3.5.1
# OS Windows 7
import socket
client = socket.socket()
client.connect(('127.0.0.1',8808,))
print(str(client.recv(1024),encoding='utf-8'))
while True:
send_file = input('>>:').strip()
if send_file == 'exit':break
send_data = bytes(send_file,encoding='utf-8')
client.sendall(send_data)
print(str(client.recv(1024),encoding='utf-8'))
client.close()