一、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 I/O Basic

    /* 记住每个类相应的用法*/流的分类: io包内定义了所有的流 分类: 方向:输入流.输出流 处理数据单位:字节流.字符流 功能不同:节点流.处理流 所有流类型,位于java.io包内,分别继承以下 ...

  2. asp.net 中 UEditor 图片和附件上传失败的处理方法

    1.0 找到 net 文件夹下面的 web.config 配置文件,注释掉如下的两句: 2.0 Uploader文件默认属性为编译,将其属性改为内容以后重新运行程序,图片上传成功. 3.0 删除 im ...

  3. zju(2)vivi的配置编译和固化

    1.实验目的 熟悉vivi的知识和应用并使用交叉编译平台vivi引导并烧写到目标板. 二.实验内容 1. 在Ubuntu下配置vivi并进行交叉编译: 2. 将编译好的vivi烧写到目标板上. 三.主 ...

  4. SVN 的安装与配置

    1.下载subclipse1.6的site包 2.把这个site-1.6.2解压开,将其内部的文件,全部放到 C:\Program Files\MyEclipse\MyEclipse 9\dropin ...

  5. WordPress插件开发实例教程 - 版权插件

    说明:本教程仅限学习,高手请绕道 开发程序:WordPress 3.9-RC1 使用主题:Twenty Fourteen 在开始之前,需要注意三件事情 I.给插件取一个个性化的名字,越个性化越好,以防 ...

  6. NY-字符串替换

    描述编写一个程序实现将字符串中的所有"you"替换成"we" 输入 输入包含多行数据 每行数据是一个字符串,长度不超过1000 数据以EOF结束 输出 对于输入 ...

  7. 关于Java擦除特性

    package thinkingInJava; /* * 模拟擦除 */ public class SimpleHolder { private Object obj ; public void se ...

  8. IOS第九天(1:QQ聊天界面frame模型)

    ///  控制层 #import "HMViewController.h" #import "HMMessageModel.h" #import "H ...

  9. Windows内核 基本数据结构

    驱动对象: 每个驱动程序都会有唯一的驱动对象与之对应,并且这个驱动对象是在驱动加载时被内核中的对象管理程序所创建的.驱动对象用DRIVER_OBJECT数据结构表示,它作为驱动的一个实例被内核加载,并 ...

  10. linux命令学习(1):grep 命令

    Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则表达 ...