IO多路复用select模块加socket模块,伪多线并发,并不是真正的多线程并发,实际通过循环等待还是一个一个处理的

IO多路复用,lo就是文件或数据的输入输出,IO多路复用就是可以多用户操作

IO多路复用,可以监听多个文件描述符(socke对象)(文件句柄),一旦文件句柄出现变化,即可感知到,感知到后作出相应操作

比如原生socke模块只能监听一个端口和只能一个用户连接,要想实现监听多个端口和支持多用户,就会使用IO多路复用

IO多路复用select模块

select()自动监听socket对象的客户端,连接地址和、客户端通讯地址,四个参数

select()自动监听列表里的socket对象(文件描述符),一旦监听的对象,谁发生了变化(有用户请求),
就将发生变化对象的客户端连接地址赋值给第一个变量a,第一个变量接收的列表,列表里的每一个元素,就是一个端口的用户连接地址
如果是多个端口在同时连接客户端,那么列表元素就是多个元素

最多监听端口1024个

使用方法:a, b, c = select.select(列表类型的socke对象变化, [可选:传参直接赋值给第二个变量], [可选:列表类型的socke对象监听错误], 多少秒检测一次)

  需要四个参数 

  参数一:列表类型的socke对象,监听变化

  参数二:传参直接赋值给第二个变量

  参数三:列表类型的socke对象,监听错误

  参数四:多少秒检测一次

  需要三个变量来接收返回值

  第一个变量接收的:列表类型客户端连接地址,如果无客户端连接则为空列表

  第二个变量接收的:第二个参数的值

  第三个变量接收的:第三个参数监听socke对象的错误信息,返回列表,无错误则为空列表

格式:a, b, c = select.select(lib, [], [], 1)

格式2:a, b, c = select.select(lib, k1, lib, 1)

IO多路复用多端口监听客户端连接地址、服务端代码

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""服务端"""
import socket #导入模块
"""设置多个对象,绑定不同端口"""
k1 = socket.socket() #创建对象
k1.bind(('127.0.0.1', 9991)) #绑定服务端IP和端口
k1.listen() #监听IP和端口 k2 = socket.socket() #创建对象
k2.bind(('127.0.0.1', 9992)) #绑定服务端IP和端口
k2.listen() #监听IP和端口 k3 = socket.socket() #创建对象
k3.bind(('127.0.0.1', 9993)) #绑定服务端IP和端口
k3.listen() #监听IP和端口
"""将多个对象组合成列表"""
lib = [k1, k2, k3] """使用自动监听模块"""
import select #导入自动监听多个端口模块
while True:
#select()自动监听列表里的socket对象(文件描述符),一旦监听的对象,谁发生了变化(有用户请求),
# 就将发生变化对象的客户端连接地址赋值给第一个变量a,第一个变量接收的列表,列表里的每一个元素,就是一个端口的用户连接地址
#如果是多个端口在同时连接客户端,那么列表元素就是多个元素
a, b, c = select.select(lib, [], [], 1)
for k in a: #循环出select()获取到的列表类型客户端连接地址
d, e = k.accept() #将循环到的每一个客户端连接地址等待通讯,阻塞
d.sendall(bytes("欢迎访问", encoding="utf-8")) #向连接的客户端发送一条消息

客户端代码1

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""创建客户端"""
import socket #导入模块
z = socket.socket() #创建socket对象
b = z.connect(('127.0.0.1', 9991,))#连接服务端,在客户端绑定服务端IP和端口 f = z.recv(1024) #客户端接收服务端sendall()发来的信息,1024表示最大接收1024字节
f2 = str(f, encoding='utf-8') #将接收到的服务端字节信息转换成字符串
print(f2) #打印出服务端发来的信息

客户端代码2

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""创建客户端"""
import socket #导入模块
z = socket.socket() #创建socket对象
b = z.connect(('127.0.0.1', 9992,))#连接服务端,在客户端绑定服务端IP和端口 f = z.recv(1024) #客户端接收服务端sendall()发来的信息,1024表示最大接收1024字节
f2 = str(f, encoding='utf-8') #将接收到的服务端字节信息转换成字符串
print(f2) #打印出服务端发来的信息

IO多路复用多端口监听、客户端连接地址原理图

IO多路复用监听客户端多通讯地址

通过select()监听到客户端变化信息对象,拿到变化信息对象,判断是连接信息对象,还是通讯信息对象?如果是连接信息对象,通过变化信息对象获取到此连接的通讯对象,将通讯对象添加到select()里监听,如果是通讯对象,通过通讯对象进行信息交互

IO多路复用监听客户端多通讯地址服务端代码

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""服务端"""
import socket #导入模块
k1 = socket.socket() #创建对象
k1.bind(('127.0.0.1', 9991)) #绑定服务端IP和端口
k1.listen() #监听IP和端口
lib = [k1] """使用自动监听模块"""
import select #导入自动监听多个端口模块
while True:
#select()自动监听列表里的socket对象(文件描述符),一旦监听的对象,谁发生了变化(有用户请求),
# 就将发生变化对象的客户端连接地址赋值给第一个变量a,第一个变量接收的列表,列表里的每一个元素,就是一个端口的用户连接地址
#如果是多个端口在同时连接客户端,那么列表元素就是多个元素
a, b, c = select.select(lib, [], [], 1)
print("正在监听的socket对象 %d" % len(lib)) #监听的对象有多少个
print(a) #监听发生变化的有哪些
for k in a: #循环出select()获取到的列表类型客户端连接地址
if k == k1: #判断循环到的连接地址等于socket对象,说明有新用户连接
d, e = k.accept() #等待请求,获取客户端通讯地址
lib.append(d) #将客户端通讯地址追加到列表,传入select()监听通讯变化
d.sendall(bytes("你好", encoding="utf-8"))
else: #如果不是连接信息,说明是通讯信息
try: #监控代码是否出现异常,如果客户端关闭了就会出现异常,没出现异常执行里面的代码
fd = k.recv(1024)
f = str(fd, encoding="utf-8")
g = f + "好"
k.sendall(bytes(g, encoding="utf-8"))
except Exception as ex: #出现异常将当前通讯对象移除列表,select不在监听
lib.remove(k)

客户端代码

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""创建客户端"""
import socket #导入模块
z = socket.socket() #创建socket对象
b = z.connect(('127.0.0.1', 9991,))#连接服务端,在客户端绑定服务端IP和端口
while True:
f = z.recv(1024) #客户端接收服务端sendall()发来的信息,1024表示最大接收1024字节
f2 = str(f, encoding='utf-8') #将接收到的服务端字节信息转换成字符串
print(f2) #打印出服务端发来的信息
a = input("输入要发送的信息")
z.sendall(bytes(a, encoding="utf-8"))

IO多路复用监听客户端多通讯原理图

IO多路复用,有三种方式(select)、(poll)、(epoll) select和poll其实都是调用计算机底层来实现的监听处理,epoll是异步处理的是文件描述符发生变化后主动告诉epoll的,这里我们需要知道一下

注意:wds系统只支持select模块,

利用select()的第二个参数,实现IO多路复用,服务端读写分离
也就是读和写分开,在不同的代码块

服务端读写分离代码

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""服务端实现读写分离"""
import socket #导入模块
k1 = socket.socket() #创建对象
k1.bind(('127.0.0.1', 9991)) #绑定服务端IP和端口
k1.listen() #监听IP和端口 lib = [k1] #监听的客户连接地址或,客户通讯地址,传给select第一个参数
lib2 = [] #接收客户端通讯地址,传给select第二个参数
jilu = {} #接收字典,里面是客户端发通讯内容的用户通讯地址(键)和通讯内容(值) """使用自动监听模块"""
import select #导入自动监听多个端口模块
while True:
#select()自动监听列表里的socket对象(文件描述符),一旦监听的对象,谁发生了变化(有用户请求),
# 就将发生变化对象的客户端连接地址赋值给第一个变量a,第一个变量接收的列表,列表里的每一个元素,就是一个端口的用户连接地址
#如果是多个端口在同时连接客户端,那么列表元素就是多个元素
a, b, c = select.select(lib, lib2, lib, 1)
print("正在监听的socket对象 %d" % len(lib)) #监听的对象有多少个
print(a) #监听发生变化的有哪些
"""循环判断链接地址或通讯地址,获取客户端通讯信息以及内容"""
for k in a: #循环出select()获取到的列表类型客户端连接地址
if k == k1: #判断循环到的连接地址等于socket对象,说明有新用户连接
d, e = k.accept() #等待请求,获取客户端通讯地址
lib.append(d) #将客户端通讯地址追加到列表,传入select()监听通讯变化
jilu[d] = [] #将连接用户通讯地址添加到字典为键,值为空列表
else: #如果不是连接信息,说明是通讯信息
try: #监控代码是否异常
fd = k.recv(1024) #获取客户端发的信息
except Exception as e: #如果异常将此通讯地址移除列表,停止监听
lib.remove(k) #通讯地址移除列表
else:
fd2 = str(fd, encoding="utf-8") #接收客户端发的信息转换成字符串
jilu[k].append(fd2) # 将客户端转换的字符串追加到,字典里当前客户键的,列表里为值
lib2.append(k) #将当前客户通讯地址,添加到select第二个参数列表里
"""向客户端发信息"""
for km in b: #循环select第二个参数列表里的通讯用户
jkd = jilu[km][0] #通过通讯用户拿到字典里对应的通讯内容
del jilu[km][0] #拿到通讯内容后删除通讯内容
km.sendall(bytes(jkd+"好", encoding="utf-8")) #将通讯内容加个好字,在发给客户端
lib2.remove(km ) #在通讯列表移除当前通讯地址 for fh in c: #如果监听连接出现异常
lib.remove(fh) #移除当前连接

客户端代码

#!/usr/bin/env python
# -*- coding:utf8 -*-
"""创建客户端"""
import socket #导入模块
z = socket.socket() #创建socket对象
b = z.connect(('127.0.0.1', 9991,))#连接服务端,在客户端绑定服务端IP和端口
while True:
a = input("输入要发送的信息")
z.sendall(bytes(a, encoding="utf-8"))
f = z.recv(1024) #客户端接收服务端sendall()发来的信息,1024表示最大接收1024字节
f2 = str(f, encoding='utf-8') #将接收到的服务端字节信息转换成字符串
print(f2) #打印出服务端发来的信息

IO多路复用,服务端读写分离原理图

第五十五节,IO多路复用select模块加socket模块,伪多线并发的更多相关文章

  1. 第三百五十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—数据收集(Stats Collection)

    第三百五十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—数据收集(Stats Collection) Scrapy提供了方便的收集数据的机制.数据以key/value方式存储,值大多是计数 ...

  2. 第三百五十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装

    第三百五十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装 elasticsearch(搜索引擎)介绍 ElasticSearch是一个基于 ...

  3. 第三百五十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy分布式爬虫要点

    第三百五十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy分布式爬虫要点 1.分布式爬虫原理 2.分布式爬虫优点 3.分布式爬虫需要解决的问题

  4. 第三百五十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy信号详解

    第三百五十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy信号详解 信号一般使用信号分发器dispatcher.connect(),来设置信号,和信号触发函数,当捕获到信号时执行 ...

  5. 第三百五十五天 how can I 坚持

    快一年了,三百五十五天了,等写个程序算算时间,看看日期和天数能不能对的上,哈哈. 计划还是未制定,天气预报还是没有写完,立马行动,发完这个博客,立马行动. 计划:设计模式1个月,三大框架3个月,计算机 ...

  6. Linux IO多路复用 select

    Linux IO多路复用 select 之前曾经写过简单的服务器,服务器是用多线程阻塞,客户端每一帧是用非阻塞实现的 后来发现select可以用来多路IO复用,就是说可以把服务器这么多线程放在一个线程 ...

  7. “全栈2019”Java第五十五章:方法的静态绑定与动态绑定

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. io多路复用-select()

    参照<Unix网络编程>相关章节内容,实现了一个简单的单线程IO多路复用服务器与客户端. 普通迭代服务器,由于执行recvfrom则会发生阻塞,直到客户端发送数据并正确接收后才能够返回,一 ...

  9. 孤荷凌寒自学python第五十五天初识MongoDb数据库

    孤荷凌寒自学python第五十五天第一天初识MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 大家好,2019年新年快乐! 本来我想的是借新年第一天开始,正式尝试学习爬虫,结果今天偶然发现 ...

随机推荐

  1. java基础练习 4

    import java.util.Scanner; public class Forth { public static void main(String[] args){ /*请输入星期几的第一个字 ...

  2. CART分类与回归树与GBDT(Gradient Boost Decision Tree)

    一.CART分类与回归树 资料转载: http://dataunion.org/5771.html        Classification And Regression Tree(CART)是决策 ...

  3. DW,DM,ODS的区别

    数据仓库的重要应用是将不同来源的数据和异构数据通过ETL整合在一起,为决策分析提供支撑,若在同一个数据库中分不同用户,此意义不大:假设所有有用户都在一个数据库里,如果因为某个原因数据库重启,那么会影响 ...

  4. dev gridcontrol把event事件转换成命令

    可以通过继承gridcontrol的形式来实现 定义DataGridDoubleClickCommand依赖属性 class MyGridControl : GridControl    {      ...

  5. Girl Develop It Chapter Leaders at 2015 Annual Leadership Summit

    Girl Develop It Chapter Leaders at 2015 Annual Leadership Summit Corinne Warnshuis, Executive Direct ...

  6. Tweak 中系统方法写入文件到根目录下面失败

    Tweak 中系统方法写入文件到根目录下面失败 失败原因: Error Domain=NSCocoaErrorDomain Code=513 "The operation couldn’t ...

  7. sparksql中行转列

    进入sparksql beeline -u "jdbc:hive2://172.16.12.46:10015" -n spark -p spark -d org.apache.hi ...

  8. 【C#】面试题整理

    1.C#中类是否支持多继承?请说明原因.答:不支持,需要用接口来实现多继承 2.我们都知道一个类可以有多个构造函数,并且C#会在我们创建类的时候默认的提供一个无参的构造函数,当我实现了另外一个有参数的 ...

  9. python3数据结构

    列表 list.append(x) 把一个元素添加到列表的结尾,相当于a[len(a):]=[x] list.extend(L) 将一个给定列表中的所有元素都添加到另一个列表中,相当于a[(len): ...

  10. 使用Jax-rs 开发RESTfull API 入门

    使用Jax-rs 开发RESTfull API 入门 本文使用 Jersey 2开发RESTfull API.Jersey 2 是 JAX-RS 接口的参考实现 使用到的工具 Eclipse Neon ...