Python—I/O多路复用
一、I/O多路复用概念:
监听多个描述符的状态,如果描述符状态改变,则会被内核修改标志位,从而被进程获取进而进行读写操作
二、select,poll,epoll
select模块,提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用。
Windows Python:
提供: select Mac Python:
提供: select Linux Python:
提供: select、poll、epollselect
在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多路复用的更多相关文章
- {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) 五 ...
- python之IO多路复用
在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...
- 【python】-- IO多路复用(select、poll、epoll)介绍及实现
IO多路复用(select.poll.epoll)介绍及select.epoll的实现 IO多路复用中包括 select.pool.epoll,这些都属于同步,还不属于异步 一.IO多路复用介绍 1. ...
- python中IO多路复用、协程
一.IO多路复用 IO多路复用:检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写) import socket def get_data(key): client ...
- 09 Python之IO多路复用
四种常见IO模型 阻塞IO(blocking IO).非阻塞IO(nonblocking IO).IO多路复用(IOmultiplexing).异步IO(asynchronous IO) IO发生时涉 ...
- Python poll IO多路复用
一.poll介绍 poll本质上和select没有区别,只是没有了最大连接数(linux上默认1024个)的限制,原因是它基于链表存储的. 本人的另一篇博客讲了 python select : ht ...
- Python select IO多路复用
一.select介绍 Python的select()函数是底层操作系统实现的直接接口.它监视套接字,打开文件和管道(任何带有返回有效文件描述符的fileno()方法),直到它们变得可读或可写,或者发生 ...
- python I/O多路复用 使用http完成http请求
1. 使用类实现比较方便我们使用里面的参数 2. 我们使用selector,不适用select from selectors import DefaultSelector 3. I/O多路复用是指使用 ...
- python 并发编程 多路复用IO模型
多路复用IO(IO multiplexing) 这种IO方式为事件驱动IO(event driven IO). 我们都知道,select/epoll的好处就在于单个进程process就可以同时处理多个 ...
随机推荐
- android-Activity(四大组件之一)
一.Activity理解 1.定义: 直译为活动,是Android定义四大应用组件之一,也是最重要的用的最多的: 用来提供一个能让用户操作并与之交互的界面 一个应用有多个界面也就是包含多个Activi ...
- LeetCode(43. Multiply Strings)
题目: Given two numbers represented as strings, return multiplication of the numbers as a string. Note ...
- JAVA中JDBC连接数据库
这里列举了JDBC连接Oracle . SQLServer .MySQL 三种 数据库 1.Oracle连接(导入classes12.jar 包) public static Connection g ...
- Js闭包常见三种用法
Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...
- 修改wamp默认网站目录
使用WAMP集成环境,如何更改web根目录 做php开发使用WAMP集成环境的同学大部分有过这样的经历: 如果你试图修改web根目录,那么你肯定会想到要修改apache/apache2.2.11/co ...
- Rocky4.2下安装金仓v7数据库(KingbaseES)
1.准备操作系统 1.1 系统登录界面 1.2 操作系统版本信息 jdbh:~ # uname -ra Linux jdbh -x86_64 # SMP Fri Dec :: CST x86_64 G ...
- 使用context来传递数据,一个context是一系列变量
页面设计工作和python代码分离,所以我们引用模板来实现这个功能. 一.模板实例 下面是一个模板的实例: [python]<html><head><title>O ...
- IOS第18天(10,核心动画-转盘,自定义buton,旋转动画)
*****HMViewController.m #import "HMViewController.h" #import "HMWheelView.h" @in ...
- Debug阶段成员贡献分
组名:天天向上 组长:王森 组员:张政.张金生.林莉.胡丽娜 Debug阶段各组员的贡献分分配如下: 姓名 个人工作量 组长评价 个人评价 团队贡献总分 张金生 11 7 6 6.00 张政 11 6 ...
- Cocos2dx集成于windows桌面窗口程序的步骤
2D游戏需要做编辑器,而编辑器总是希望可以复用游戏中的逻辑来运行场景试看效果. 对于cocos2dx开发的程序,这个需求可以描述为: 实现一种方法,在桌面窗口程序中的某个控件上显示cocos2dx的场 ...