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多路复用,服务端读写分离原理图

转载于:https://www.cnblogs.com/adc8868/p/5915181.html

第五十五节,IO多路复用select模块加socket模块,伪多线并发相关推荐

  1. Python编程基础:第五十九节 守护线程Daemon Threading

    第五十九节 守护线程Daemon Threading 前言 实践 前言 守护线程是在后台运行的线程,对程序的运行并不重要,你的程序在退出前不会等待守护线程的完成,此类线程的特点是,当程序中主线程及所有 ...

  2. Python编程基础:第五十六节 filter函数Filter

    第五十六节 filter函数Filter 前言 实践 前言 filter函数的作用是对可迭代对象内部的元素按照特定条件进行过滤,其书写方式为filter(function, iterable),第一个 ...

  3. Python编程基础:第五十五节 map函数Map

    第五十五节 map函数Map 前言 实践 前言 map函数的作用是将指定函数作用于一个可迭代对象内部的每一个元素,其表达方式为map(function, iterable),第一个位置指定作用函数,第 ...

  4. Python编程基础:第五十四节 排序Sort

    第五十四节 排序Sort 前言 实践 前言 我们常需要对列表.元组中的元素进行排序,例如按照字母表排列学生的名称.这里就需要用到列表的sort()方法,以及sorted()函数. 实践 我们先来构建一 ...

  5. 我的世界服务器群系修改,我的世界创世神教程 第五十五节修改选区的生物群系|功能介绍|难点介绍|这节...

    我的世界WorldEdit创世神高级系列教程 第五十五节修改选区的生物群系.本教程由64条不同的技巧,功能介绍,难点介绍,防范措施介绍,工具介绍等组成.适合高级玩家和腐竹们来学习.这节内容给大家介绍修 ...

  6. 【零基础学Java】—Socket类(五十五)

    [零基础学Java]-Socket类(五十五) Socket类:该类实现客户端套接字,套接字是指两台设备之间通讯的端点. 在Java中,提供了两个类用于实现TCP通信程序 客户端:java.net.S ...

  7. 【Visual C++】游戏开发五十五 浅墨DirectX教程二十二 水乳交融的美学:alpha混合技术

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/15026917 作者:毛星 ...

  8. JavaScript学习(五十五)—组合继承

    JavaScript学习(五十五)-组合继承 组合继承:就是借用构造方法继承和原型链继承的组合形式

  9. 信息系统项目管理师核心考点(五十五)配置管理员(CMO)的工作

    科科过为您带来软考信息系统项目管理师核心重点考点(五十五)配置管理员(CMO)的工作,内含思维导图+真题 [信息系统项目管理师核心考点]配置管理员(CMO)的工作 1.制定配置管理计划 2.识别配置项 ...

  10. 达芬奇密码 第五十五章 第五十六章

    达芬奇密码 第五十五章 第五十六章[@more@] 第五十五章 索菲靠着兰登坐在长沙发上,喝着茶吃着烤饼,享受着食物的美味.雷·提彬爵士微笑着,在炉火前面笨拙地踱来踱去.假肢敲在地面上,发出" ...

最新文章

  1. Python的闭包和装饰器
  2. html region 折叠,js代码折叠的方法//#region 代码 //#endregion
  3. 最终成为了热门的语言——python
  4. Ubuntu安装及配置OpenCV3.2.0
  5. kettle组件-查询
  6. 用符号方法求下列极限或导数matlab,实验7答案 Matlab符号计算
  7. Index of open source
  8. TensorFlow学习笔记(二十一) tensorflow机器学习模型
  9. cad线性标注命令_CAD线性标注如何使用的
  10. vs 2008 Ide 设置
  11. vue ---- 动态组件
  12. Java集合类的整理
  13. 力扣-746. 使用最小花费爬楼梯
  14. leetcode 859. Buddy Strings
  15. 企业采用IT人才外包会有这么多好处
  16. MD5加密中文字符问题详解
  17. 读文献——《Curriculum learning》
  18. 新的一年强势推荐5个免费的在线工具
  19. 机器学习训练过程中常见问题
  20. rockchip研讨会_地下在线研讨会6

热门文章

  1. mysql 取字段内容的第一个字符并大写
  2. 2 BeeGo 参数配置与路由配置
  3. IT十八掌掌第十一天课程总结
  4. U-boot在S3C2440上的移植详解(二)
  5. [Android] 环境配置之正式版Android Studio 1.0
  6. [Java][Android][Process] 分享 Process 执行命令行封装类
  7. Luogu4114 Qtree1
  8. 自定义Promise
  9. python如何向服务器发送文件,在Python中使用套接字向服务器发送文件
  10. linux office转pdf python_使用python写的PDF转EXCEL工具,已打包exe