一、I/O多路复用概念:

  监听多个描述符的状态,如果描述符状态改变,则会被内核修改标志位,从而被进程获取进而进行读写操作

二、select,poll,epoll

select模块,提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。

  Windows Python:提供: select
  Mac Python:提供: select
  Linux Python:提供: select、poll、epoll
 

select 

  在python中,select函数是一个对底层操作系统的直接访问的接口,它用来监控sockets、files和pipes,等待IO完成。当有可读、可写或是异常事件产生时,select可以很容易的监控到。

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,这也是它所剩不多的优点之一。

select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏提升这一限制。

格式:rList,wList,eList = select.select(argv1,argv2,argv3,timeout)

参数:

  argv1:监听序列中的句柄发生变化时,则获取发生变化的句柄添加到rList序列中

  argv2:监听序列中含有句柄时,则将该序列中所有的句柄添加到wList序列中

  argv3:监听序列中的句柄发生错误时,则将该发生错误的句柄添加到eList序列中

  timeout:设置阻塞时间,如果不设置则默认一直阻塞

select 实例:

  用select实现处理多个socket客户端请求

服务端

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import select
ip_port = ('127.0.0.1',9999) sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象
sk.bind(ip_port) #绑定ip、端口
sk.listen(5) #监听
sk.setblocking(False) #不阻塞 inputs = [sk,]
outputs = []
while True:
rlist,wlist,eList = select.select(inputs,outputs,[],0.5)
print("inputs:",inputs) #查看inputs列表变化
print("rlist:",rlist) #查看rlist列表变化
for r in rlist:
if r == sk: #如果r是服务端
conn,address = r.accept()#
inputs.append(conn)
print (address)
else:
client_data = r.recv(1024)
if client_data: #如果有数据,返回数据
r.sendall(client_data)
else: #否则移除
inputs.remove(r)

客户端:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
ip_port = ('127.0.0.1',9999) sk = socket.socket() #创建socket对象
sk.connect(ip_port) #通过ip和端口连接server端
while True:
inpu=input(">>:")
sk.sendall(bytes(inpu,"utf8")) #给server端发送信息 server_reply = sk.recv(1024) #接受消息
print (str(server_reply,"utf8")) #打印消息 sk.close() #关闭连接

过程:

启动服务端,这时select会一直监听服务端句柄,直到有客户端请求过来发生变化。

当客户端有新的连接请求过来时,select捕捉到服务端句柄发生变化,把变化的句柄加入到rlist,所以这时r == sk,接收这个链接并把句柄加入到inputs列表,

现在,select监听的就是两个句柄了。同理,当有多个链接请求过来时,都会把它添加到inputs列表中。

当其中的一个客户端A发送信息过来时,select会在监听的句柄列表中捕捉到客户端A这个句柄发生了变化,并把发生变化的句柄加入到rlist,但这时r不等于sk,

执行另一步操作,接收返回数据。

上面讲到了argv1参数的概述,是监听argv1这个列表,当有发生变化时才会捕捉,并加入到rlist。

argv2参数:只要在这个列表里有值,每次都会加入到wList,不同于argv1

所以可以利用argv2参数实现读写分离

server端

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import select
import queue
ip_port = ('127.0.0.1',9999) sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象
sk.bind(ip_port) #绑定ip、端口
sk.listen(5) #监听
sk.setblocking(False) #不阻塞 inputs = [sk,]
outputs = []
message={}
while True:
rlist,wlist,eList = select.select(inputs,outputs,[],0.5)
#print("inputs:",inputs) #查看inputs列表变化
#print("rlist:",rlist) #查看rlist列表变化
#print(message)
for r in rlist:
if r == sk: #如果r是服务端
conn,address = r.accept()#
inputs.append(conn) #把连接的句柄加入inputs列表监听
message[conn] = queue.Queue() #每个新的句柄对应一个队列
print (address)
else:
client_data = r.recv(1024)
if client_data: #如果有数据,返回数据
outputs.append(r)
message[r].put(client_data) #在指定队列中插入数据
else:
inputs.remove(r) #否则移除
del message[r] #删除队列 for w in wlist: #如果wlist列表有值
try:
data =message[w].get_nowait()#去指定队列取数据
w.sendall(data)
except queue.Empty:
pass
outputs.remove(w)#因为output列表只要有数据每次都会加入wlist列表,所以发送完数据都要移除

在argv3的监听列表中,如果在跟某个socket连接通信过程中出了错误,就会把错误的句柄加到eList ,所以在加个判断,当某个socket连接通信过程中出了错误,就把这个错误的连接对象在各个列表和字典中删除。

在循环里在加上一个判断

  for e in eList:
inputs.remove(e)#删除inputs监听的错误句柄
if e in outputs:#如果outputs里有也删除
outputs.remove(e)
e.close()
del message[e] #删除队列

select的4个参数都介绍完后附上server端完整代码

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import select
import queue
ip_port = ('127.0.0.1',9999) sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #创建socket对象
sk.bind(ip_port) #绑定ip、端口
sk.listen(5) #监听
sk.setblocking(False) #不阻塞 inputs = [sk,]
outputs = []
message={}
while True:
rlist,wlist,eList = select.select(inputs,outputs,inputs,0.5)
#print("inputs:",inputs) #查看inputs列表变化
#print("rlist:",rlist) #查看rlist列表变化
#print(message)
for r in rlist:
if r == sk: #如果r是服务端
conn,address = r.accept()#
inputs.append(conn) #把连接的句柄加入inputs列表监听
message[conn] = queue.Queue() #每个新的句柄对应一个队列
print (address)
else:
client_data = r.recv(1024)
if client_data: #如果有数据,返回数据
outputs.append(r)
message[r].put(client_data) #在指定队列中插入数据
else:
inputs.remove(r) #否则移除
del message[r] #删除队列 for w in wlist: #如果wlist列表有值
try:
data =message[w].get_nowait()#去指定队列取数据
w.sendall(data)
except queue.Empty:
pass
outputs.remove(w)#因为output列表只要有数据每次都会加入wlist列表,所以发送完数据都要移除 for e in eList:
inputs.remove(e)#删除inputs监听的错误句柄
if e in outputs:#如果outputs里有也删除
outputs.remove(e)
e.close()
del message[e] #删除队列

参考:http://www.cnblogs.com/wupeiqi/articles/5040823.html

Python—I/O多路复用的更多相关文章

  1. {python之IO多路复用} IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) IO模型比较分析 selectors模块

    python之IO多路复用 阅读目录 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 ...

  2. python之IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

  3. 【python】-- IO多路复用(select、poll、epoll)介绍及实现

    IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...

  4. python中IO多路复用、协程

    一.IO多路复用 IO多路复用:检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写) import socket def get_data(key): client ...

  5. 09 Python之IO多路复用

    四种常见IO模型 阻塞IO(blocking IO).非阻塞IO(nonblocking IO).IO多路复用(IOmultiplexing).异步IO(asynchronous IO) IO发生时涉 ...

  6. Python poll IO多路复用

    一.poll介绍 poll本质上和select没有区别,只是没有了最大连接数(linux上默认1024个)的限制,原因是它基于链表存储的. 本人的另一篇博客讲了 python  select : ht ...

  7. Python select IO多路复用

    一.select介绍 Python的select()函数是底层操作系统实现的直接接口.它监视套接字,打开文件和管道(任何带有返回有效文件描述符的fileno()方法),直到它们变得可读或可写,或者发生 ...

  8. python I/O多路复用 使用http完成http请求

    1. 使用类实现比较方便我们使用里面的参数 2. 我们使用selector,不适用select from selectors import DefaultSelector 3. I/O多路复用是指使用 ...

  9. python 并发编程 多路复用IO模型

    多路复用IO(IO multiplexing) 这种IO方式为事件驱动IO(event driven IO). 我们都知道,select/epoll的好处就在于单个进程process就可以同时处理多个 ...

随机推荐

  1. java web(三) Tomcat虚拟目录映射方式

    Tomact服务器虚拟目录的映射方式 web应用开发好后若想被外界访问,需要将web应用所在的目录交给web服务器管理,这个过程称为虚拟目录的映射. 方式一:在server.xml文件的host元素中 ...

  2. 完美扫描PHP特殊一句话后门

    <?php /********************** 作者 Spider 网上公布的各种PHP后门全军覆没 针对一些特殊变形的后门需要自己添加特征 误报率不到百分之一 ********** ...

  3. 使用文件模拟ASM磁盘

    尽管Oracle缺省都是使用裸设备来创建ASM磁盘,但其实Oracle也允许使用普通文件来创建ASM磁盘, 当然这种方法最好只用在测试环境下或者学习环境下,不能用在生产环境下.之所以必须要用裸设备, ...

  4. 2016HUAS暑假集训训练题 F - 简单计算器

    Description 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值.    Input 测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运 ...

  5. Eclipse 官方简体中文语言包下载地址及安装方法

    Eclipse 官方简体中文语言包下载地址及安装方法 打开Eclipse Babel Project 主页: http://www.eclipse.org/babel/downloads.php 根据 ...

  6. js sort() 排序的问题

    默认并非按照大小排序,而是根据Assic来排序的,但接受一个排序函数.所以正确的使用姿势应该是这样的: var arr = [0,1,5,10,15]; function sequence(a,b){ ...

  7. 温故而知新,jquery选择器$=

    $("select[name$=Sort]") 可以选择到如下元素: <select class="sort-selec" name="eton ...

  8. ModSecurity 白名单设置

    方法一.SecRuleRemoveById 指令:通过Rule ID禁用指定规则 #waf whitelist <LocationMatch .*> SecRuleRemoveById 9 ...

  9. 禁止COOKIE后对SESSION的影响

    一.理解SESSION机制 简单来说:每一个SESSION都有一个唯一的session_id , 默认情况下,session_id存储在客户端(默认COOKIE['PHPSESSID']), 在使用S ...

  10. awk脚本

    $0,意即所有域. 有两种方式保存shell提示符下awk脚本的输出.最简单的方式是使用输出重定向符号>文件名,下面的例子重定向输出到文件wow. #awk '{print $0}' grade ...