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. CentOS7 下 yum 安装 Docker CE

    前言 Docker 使用越来越多,安装也很简单,本次记录一下基本的步骤. Docker 目前支持 CentOS 7 及以后的版本,内核要求至少为 3.10. Docker 官网有安装步骤,本文只是记录 ...

  2. [转帖]spring、springMvc、springBoot和springCloud的联系与区别

    spring.springMvc.springBoot和springCloud的联系与区别 -- :: 尘光掠影 阅读数 文章标签: springspringmvcspringbootspringCl ...

  3. Qt3D NodeInstantiator 使用时报出index out of range错误的记录

    最近用到NodeInstantiator批量加入实体 刚开始用的时候一直程序崩溃 错误代码大致如下: // main.qml ApplicationWindow { ...... Loader { i ...

  4. Golang解析、验证、修改URL之Host、Port、Path

    URL解析验证问题 net.ParseIP()只能解析不带冒号以及端口号的IP4/IP6 ✔: 127.0.0.1.2001:db8::68 ✖: 127.0.0.1:8080.www.baidu.c ...

  5. FPGA 软件平台

    FPGA软件平台 系统 --> windows 7 xilinx --> vivado 2016.4 xilinx --> ISE 14.7 Altera --> quartu ...

  6. 菜刀连接一句话木马出现:`Cannot call assert() with string argument dynamically`错误

    前言 逆天还是上学那会玩渗透的,后来工作后就再也没碰了,所以用的工具还是以前经典款,这不,发现出问题了 问题 如果是PHP5则没有问题,如果是PHP7,会出现:Cannot call assert() ...

  7. arguments 使用

    function test(){ var paramsNum = arguments.length; var sum = 0; for(var i = 0;i<paramsNum;i++){ c ...

  8. expor和import的用法

    1.Export 模块是独立的文件,该文件内部的所有的变量外部都无法获取.如果希望获取某个变量,必须通过export输出 // profile.js export var firstName = 'M ...

  9. Java 之 Collection 接口

    一.Collection 集合 Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是 java.util.List 和 java.util.Set. ...

  10. 腕表wacche英语wacche手表

    watch As a noun, from Middle English wacche, Etymology As a noun, from Middle English wacche,See bel ...