1、I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
2、I/O多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理。

select
select是通过系统调用来监视一组由多个文件描述符组成的数组,通过调用select()返回结果,数组中就绪的文件描述符会被内核标记出来,然后进程就可以获得这些文件描述符,然后进行相应的读写操作

select的实际执行过程如下:

1、select需要提供要监控的数组,然后由用户态拷贝到内核态。

2、内核态线性循环监控数组,每次都需要遍历整个数组。

3、内核发现文件描述符状态符合操作结果,将其返回。

所以对于我们监控的socket都要设置为非阻塞的,只有这样才能保证不会被阻塞。

优点
基本各个平台都支持

缺点
1、每次调用select,都需要把fd集合由用户态拷贝到内核态,在fd多的时候开销会很大

2、单个进程能够监控的fd数量存在最大限制,因为其使用的数据结构是数组。

3、每次select都是线性遍历整个数组,当fd很大的时候,遍历的开销也很大

python使用select

语法:r_list, w_list, e_list = select.select( rlist, wlist, errlist [,timeout] )

说明详解:

rlist,wlist和errlist均是waitable object; 都是文件描述符,就是一个整数,或者一个拥有返回文件描述符的函数fileno()的对象。

rlist: 等待读就绪的文件描述符数组

wlist: 等待写就绪的文件描述符数组

errlist: 等待异常的数组

在linux下这三个列表可以是空列表,但是在windows上不行

当rlist数组中的文件描述符发生可读时(调用accept或者read函数),则获取文件描述符并添加到r数组中。

当wlist数组中的文件描述符发生可写时,则获取文件描述符添加到w数组中

当errlist数组中的文件描述符发生错误时,将会将文件描述符添加到e队列中

当超时时间没有设置时,如果监听的文件描述符没有任何变化,将会一直阻塞到发生变化为止

当超时时间设置为1时,如果监听的描述符没有变化,则select会阻塞1秒,之后返回三个空列表。 如果由变化,则直接执行并返回。

一、基于select实现的IO多路复用的基础实例:

io_server.py

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
IO多路复用服务器端
"""
import socket sk1 = socket.socket()
sk1.bind(('127.0.0.1', 8001))
sk1.listen(5) sk2 = socket.socket()
sk2.bind(('127.0.0.1', 8002))
sk2.listen(5) sk3 = socket.socket()
sk3.bind(('127.0.0.1', 8003))
sk3.listen(5) inputs = [sk1, sk2, sk3]
import select while True:
#[sk1, sk2, sk3],select内部启动监听sk1, sk2, sk3三个对象,一旦某个句柄发生变化
#如果有人用sk1
#r_list = [sk1, sk2, sk3]
r_list, w_list, e_list = select.select(inputs, [], [], 1)
print(r_list)
for sk in r_list:
#每一个连接对象
conn, address = sk.accept()
conn.sendall(bytes('Hello', encoding='utf-8'))
conn.close()

io_client.py

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
客户端1,请求8001端口
"""
import socket ck = socket.socket()
ck.connect(('127.0.0.1', 8001)) content = str(ck.recv(1024), encoding='utf-8')
print(content)

二、IO多路复用服务器端升级改造后的代码实现

io_server2.py

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
IO多路复用服务器端升级改造
""" import socket
import select sk = socket.socket() sk.bind(('127.0.0.1', 8001))
sk.listen() inputs = [sk,]
while True:
r_list, w_list, e_list = select.select(inputs, [], [], 1)
print('正在监听的socket对象:%d' % len(inputs))
for sk_or_conn in r_list:
#每一个连接对象
if sk_or_conn == sk:
#表示有新用户来连接
conn, address = sk.accept()
inputs.append(conn)
else:
#有老用户发消息了
try:
data_bytes = sk_or_conn.recv(1024)
except Exception as ex:
#如果有用户终断连接,则移除句柄
inputs.remove(sk_or_conn)
else:
#用户正常发送信息
data_str = str(data_bytes, encoding='utf-8')
sk_or_conn.sendall(bytes(data_str + '好', encoding='utf-8')) for sk in e_list:
inputs.remove(sk)

三、IO多路复用服务器端升级改造,读、写分离

io_server3.py

 #!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
IO多路复用服务器端升级改造,读、写分离
""" import socket
import select sk = socket.socket()
sk.bind(('127.0.0.1', 8001))
sk.listen() inputs = [sk,]
outputs = []
message_dict = {} while True: r_list, w_list, e_list = select.select(inputs, outputs, inputs, 1) print('正在监听的socket对象:%d' % len(inputs))
for sk_or_conn in r_list:
#每一个连接对象
if sk_or_conn == sk:
#表示有新用户来连接
conn, address = sk.accept()
inputs.append(conn)
#将连接的用户添加到字典中
message_dict[conn] = []
else:
#有老用户发消息了
try:
data_bytes = sk_or_conn.recv(1024)
except Exception as ex:
#如果有用户终断连接,则移除句柄
inputs.remove(sk_or_conn)
else:
# 用户正常发送信息
data_str = str(data_bytes, encoding='utf-8')
message_dict[sk_or_conn].append(data_str) #将用户发送过来的信息存在在字典中
# sk_or_conn.sendall(bytes(data_str + '好', encoding='utf-8'))
outputs.append(sk_or_conn) #写操作
for sk_out in w_list:
recv_data = message_dict[sk_out][0] #从字典中获取信息数据
del message_dict[sk_out][0] #获取数据后,清空字典,等待存储下次的数据
sk_out.sendall(bytes(recv_data + '好', encoding='utf-8'))
outputs.remove(sk_out) for sk in e_list:
inputs.remove(sk)

python--io多路复用之select实现的更多相关文章

  1. Python——IO多路复用之select模块epoll方法

    Python——IO多路复用之select模块epoll方法 使用epoll方法实现IO多路复用,使用方法基本与poll方法一致,epoll效率要高于select和poll. .├── epoll_c ...

  2. Python——IO多路复用之select模块poll方法

    Python——IO多路复用之select模块poll方法 使用poll方法实现IO多路复用 .├── poll_client.py├── poll_server.py└── settings.py ...

  3. Python——IO多路复用之select模块select方法

    Python——IO多路复用之select模块select方法 使用select模块的select方法实现Python——IO多路复用 实现同时将终端输入的文本以及客户端传输的文本写入文本文件中: w ...

  4. python网络编程——IO多路复用之select

    1 IO多路复用的概念 原生socket客户端在与服务端建立连接时,即服务端调用accept方法时是阻塞的,同时服务端和客户端在收发数据(调用recv.send.sendall)时也是阻塞的.原生so ...

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

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

  6. IO多路复用(select、poll、epoll)介绍及select、epoll的实现

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

  7. IO多路复用之select

    IO多路复用之select总结   1.基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程.IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交 ...

  8. 网络通信 --> IO多路复用之select、poll、epoll详解

    IO多路复用之select.poll.epoll详解      目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll,I/O多路复用就是通过一种机制,一个进程可以监视 ...

  9. IO多路复用之select、poll、epoll

    本文转载自IO多路复用之select.poll.epoll 导语 IO多路复用:通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. ...

  10. python基础-11 socket,IO多路复用,select伪造多线程,select读写分离。socketserver源码分析

    Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

随机推荐

  1. 2014百度之星 Information

    Information Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  2. 12. Scala模式匹配

    12.1 match 12.1.1 基本介绍 Scala中的模式匹配类似于Java中的switch语法,但是更加强大 模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需 ...

  3. sql中筛选第一条记录【分组排序】

    问题描述 我们现在有一张表titles,共有4个字段,分别是emp_no(员工编号),title(职位),from_date(起始时间),to_date(结束时间),记录的是员工在某个时间段内职位名称 ...

  4. CentOS 7 新系统 手动配置网络 简要步骤

    一.配置网卡文件 1.修改网卡文件进入网卡配置文件目录 cd /etc/sysconfig/network-scripts 2.查看网卡文件 # ls CentOS中网卡文件一般为 ifcfg-ens ...

  5. LinkedList、ArrayList、Vector三者的关系与区别?

    LinkedList.ArrayList.Vector三者的关系与区别? 区分ArrayList,Vector,LinkedList的区别 ArrayList,Vector的区别: 1.出现版本:Ar ...

  6. Python面向对象封装案例

    01. 封装 封装 是面向对象编程的一大特点 面向对象编程的 第一步 —— 将 属性 和 方法 封装 到一个抽象的 类 中 外界 使用 类 创建 对象,然后 让对象调用方法 对象方法的细节 都被 封装 ...

  7. ip2region.jar实现ip转地址

    ip转地址 根据ip地址查询出所在地址. GitHub地址 https://github.com/lionsoul2014/ip2region/ pom坐标 <dependency> &l ...

  8. Node.js 连接 MongoDB数据库

    安装指令:npm install mongodb var mongodb = require("mongodb");// console.log(mongodb); var Mon ...

  9. 在微信小程序中使用redux

    本文主要讲述,在微信小程序中如何使用redux DEMO 需要解决的问题 如何在小程序中引入redux状态管理库,及它相关的插件? 微信小程序没有清晰的异步api,便于thunkMiddleware处 ...

  10. mysql 5.7.25中ibtmp1文件过大

    问题描述 生产环境linux suse11.4, 根目录/ 下大小:50G, ibtmp1大小:31G, 磁盘空间爆满100%告警. ibtmp1文件说明 ibtmp1是非压缩的innodb临时表的独 ...