IO 模型 IO 多路复用

IO多路复用:模型(解决问题的方案)

同步:一个任务提交以后,等待任务执行结束,才能继续下一个任务

异步:不需要等待任务执行结束,

阻塞:IO阻塞,程序卡住了

非阻塞:不阻塞

IO模型:

  1. 阻塞 IO
  2. 非阻塞 IO
  3. IO 多路复用
  4. 异步 IO

阻塞 IO :

服务端:

import socket
import time server = socket.socket()
# 允许地址复用
server.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("127.0.0.1", 8001)) server.listen(5)
# 设置非阻塞
server.setblocking(False) while 1:
time.sleep(0.2)
try:
# 等待 用户链接
conn, addr = server.accept()
print(addr) except BlockingIOError:
print('在做其他的事情') # print('r_list: ', len(r_list))
# print('w_dict: ', len(w_dict))

客户端:

import socket
import time client = socket.socket() client.connect(("127.0.0.1", 8001)) while 1:
data = input(">>>>>>")
if not data:
continue
client.send(data.encode("utf-8")) print(client.recv(1024).decode("utf-8"))

非阻塞 IO:

  • 将 server 端设为 IP 地址复用 监听个数增加

  • 设为非阻塞

  • 循环 等待用户连接, 将连接的用户放入列表 未连接 会报错 处理未连接的 异常

  • 循环接收信息 处理未接收的信息 异常 强制断开异常

    强调强调强调:!!!非阻塞IO的精髓在于完全没有阻塞!!!

服务端:

import socket
import time # 在非阻塞式IO中, 用户进程其实是需要不断的主动询问kernel数据准备好了没有。 server = socket.socket()
# 允许地址复用
server.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(("127.0.0.1", 8001)) server.listen(5)
# 设置非阻塞
server.setblocking(False)
# 存放 所有已经链接的 用户 通道
r_list = []
# 存储所有 用户发送来的 消息
w_dict = {}
while 1:
time.sleep(0.2)
try:
# 等待 用户链接
conn, addr = server.accept()
# 将 已经链接的 用户放入 用户列表
r_list.append(conn)
except BlockingIOError:
pass
# 非阻塞模式下 如果没有用户链接会报错
# print(111) # print('在做其他的事情')
# print('r_list: ', len(r_list))
# print('w_dict: ', len(w_dict)) # 存放 错误的用户信息
del_list = []
for con in r_list:
try:
# 接收消息
data = con.recv(1024)
# 如果接收到 空信息 则证明 用户已经断开连接
if not data:
# 关闭 这个链接
con.close()
del_list.append(con)
continue
else:
# 将接收到的 信息 保存到列表中
w_dict[con] = data.decode("utf-8")
except BlockingIOError: # 没有收成功,则继续检索下一个套接字的接收
pass
except ConnectionResetError: # 当前套接字出异常,则关闭,然后加入删除列表,等待被清除
con.close() # 强制断开连接
del_list.append(con)
pass
# 删除 错误 链接
# print(r_list)
# 遍历写列表,依次取出套接字发送内容
del_wlist=[]
for con in del_list:
r_list.remove(con)
# print(w_dict)
# 打印所有信息 并回复
for k,v in w_dict.items():
print("用户:%s\n>>>>>>%s" % (k,v))
k.send("你还好吗?".encode("utf-8"))
# 清空信息字典
#del_rlist.clear() #清空列表中保存的已经删除的内容
for conn in del_wlist:
w_list.pop(conn)
# w_dict.clear()

客户端:

import socket
import time # 在非阻塞式IO中, 用户进程其实是需要不断的主动询问kernel数据准备好了没有。 client = socket.socket() client.connect(("127.0.0.1", 8001)) while 1:
data = input(">>>>>>")
if not data:
continue
client.send(data.encode("utf-8")) print(client.recv(1024).decode("utf-8"))

IO 多路复用 :

  • select : 代理监听所有的对象 轮训监听列表

  • 机制:

    select 机制: windows linux 自动切换 最多监听 32位机默认是1024个。64位机默认是2048.

    • 时间复杂度O(n)

    poll 机制: Linux 它没有最大连接数的限制,原因是它是基于链表来存储的

    • 时间复杂度O(n)

    epoll 机制: Linux

    • 时间复杂度O(1)

    • epoll的优点:

      1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口)

      2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;

      即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll

客户端:

import select
import socket server = socket.socket() server.bind(("127.0.0.1", 8001)) server.listen(5)
# 设置非阻塞 不等待任何IO 操作
server.setblocking(False) # 所有 监听的 列表
r_list = [server, ]
# 存放客户端发送过来的消息
r_data = {}
# 所有 有动作的 管道 列表
w_list = []
# 存放要返回给客户端的消息
w_data = {} while 1:
# 开始 select 监听,对r_list中的服务端server进行监听,select函数阻塞进程,直到r_list中的套接字被触发
# (在此例中,套接字接收到客户端发来的握手信号,从而变得可读,满足select函数的“可读”条件)
# ,被触发的(有动静的)套接字(服务器套接字)返回给了rl这个返回值里面;
rl, wl, al = select.select(r_list, w_list, [])
# 对rl进行循环判断是否有客户端连接进来,当有客户端连接进来时select将触发
for con in rl:
# 判断当前触发的是不是socket对象, 当触发的对象是socket对象时,说明有新客户端accept连接进来了
if con == server:
conn, addr = server.accept()
# 把新的客户端连接加入到监听列表中,当客户端的连接有接收消息的时候,select将被触发,会知道这个连接有动静,有消息,那么返回给rl这个返回值列表里面。
r_list.append(conn)
else:
try:
# 是客户端连接对象触发 接收消息
data = con.recv(1024)
# 没有数据的时候,我们将这个连接关闭掉,并从监听列表中移除
if not data:
con.close()
r_list.remove(con)
else:
# 存放 客户端发送过来的消息
r_data[con] = data.decode("utf-8")
# 将客户端连接对象和这个对象接收到的消息加工成返回消息,并添加到wdata这个字典里面
w_data[con] = data.upper()
# 需要给这个客户端回复消息的时候,我们将这个连接添加到wlist写监听列表中
w_list.append(con)
# 如果这个连接出错了,客户端暴力断开了(注意,我还没有接收他的消息,或者接收他的消息的过程中出错了)
except ConnectionResetError as E:
print(E)
# 关闭连接
con.close()
# 将这个链接从监听列表中删除
r_list.remove(con)
# 如果现在没有客户端请求连接,也没有客户端发送消息时,开始对发送消息列表进行处理,是否需要发送消息
for data in wl:
data.send(w_data[data])
w_data.pop(data)
w_list.remove(data) # 打印所有接收到的数据
for k, v in r_data.items():
print("用户:%s\n%s" % (k, v))
# 清空信息字典
r_data.clear()

客户端:


import socket client = socket.socket() server_ip = ("127.0.0.1", 8001)
# 链接指定的 服务端
client.connect(server_ip)
while 1:
client.send(input(">>>>>").encode("utf-8")) data = client.recv(1024).decode("utf-8")
print(data)

IO 模型 IO 多路复用的更多相关文章

  1. Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)

    Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 背景 我们在上一讲 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO中,对于其中的 阻塞/非阻塞IO 进行了 ...

  2. 【经典】5种IO模型 | IO多路复用

    上篇回顾:静态服务器+压测 3.2.概念篇 1.同步与异步 同步是指一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成. 异步是指不需要等待被依赖的任务完成,只是通 ...

  3. IO模型 IO多路复用

    阻塞IO 用socket 一定会用到accept recv recvfrom这些方法正常情况下 accept recv recvfrom都是阻塞的 非阻塞IO 如果setblocking(False) ...

  4. 五种网络IO模型以及多路复用IO中select/epoll对比

    下面都是以网络读数据为例 [2阶段网络IO] 第一阶段:等待数据 wait for data 第二阶段:从内核复制数据到用户 copy data from kernel to user 下面是5种网络 ...

  5. IO模型——IO多路复用机制

    (1)I/O多路复用技术通过把多个I/O的阻塞复用到同一个select.poll或epoll的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求.与传统的多线程/多进程模型比,I/O多路复 ...

  6. Python并发编程-IO模型-IO多路复用实现SocketServer

    Server.py import select import socket sk = socket.socket() sk.bind(('127.0.0.1',8080)) sk.setblockin ...

  7. IO模型之IO多路复用 异步IO select poll epoll 的用法

    IO 模型之 多路复用 IO 多路复用IO IO multiplexing 这个词可能有点陌生,但是如果我说 select/epoll ,大概就都能明白了.有些地方也称这种IO方式为 事件驱动IO ( ...

  8. 03 高性能IO模型:采用多路复用机制的“单线程”Redis

    本篇重点 三个问题: "Redis真的只有单线程吗?""为什么用单线程?""单线程为什么这么快?" "Redis真的只有单线程吗? ...

  9. 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型

    进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...

随机推荐

  1. RabbitMQ消息队列(十一)-如何实现高可用

    在前面讲到了RabbitMQ高可用集群的搭建,但是我们知道只是集群的高可用并不能保证应用在使用消息队列时完全没有问题,例如如果应用连接的RabbitMQ集群突然宕机了,虽然这个集群时可以使用的,但是应 ...

  2. ES6躬行记(12)——数组

    ES6为数组添加了多个新方法,既对它的功能进行了强化,也消除了容易产生歧义的语法. 一.静态方法 1)of() ES6为Array对象新增的第一个静态方法是of(),用于创建数组,它能接收任意个参数, ...

  3. SpringCloud应对高并发的思路

    一.Eureka的高可用性 Eureka下面的服务实例默认每隔30秒会发送一个HTTP心跳给Eureka,来告诉Eureka服务还活着,每个服务实例每隔30秒也会通过HTTP请求向Eureka获取服务 ...

  4. c#计算机视觉库openCVSharp

    作为研究计算机视觉的一员,大家肯定对Intel大名鼎鼎的openCV系列计算机视觉库耳熟能详,对于很多人来说openCV甚至已经成为其项目研究不可缺少的一部分.但是,由于项目兼容性的要求.openCV ...

  5. 1.docker常用命令

    1.启动交互式容器 $ docker run -i -t IMAGE /bin/bash -i --interactive=true|false 默认是false -t --tty=true|fals ...

  6. JAVA-HashMap实现原理

    一.HashMap实现原理 1. HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.它允许存入null值和null键.它不保证存入元素的顺序与操作顺序一致,主要是不保证元素的顺序 ...

  7. Web前端 Web前端和Web后端的区分

    一.绪论 1. 前台:呈现给用户的视觉和基本的操作. 后台:用户浏览网页时,我们看不见的后台数据跑动.后台包括前端.后端. 前端:对应我们写的html.css.javascript 等网页语言作用在前 ...

  8. CSS 渐变色

    CSS linear-gradient() 函数 http://www.runoob.com/cssref/func-linear-gradient.html CSS radial-gradient( ...

  9. 使用Git进行版本管理

    参考:http://www.runoob.com/git/git-tutorial.html 一.Git简介 1.Git 和 SVN 比较 (1)GIT是分布式的,SVN不是; (2)GIT把内容按元 ...

  10. 自定义控制台程序导出角色对实体的权限为Excel文件

    本人微信公众号:微软动态CRM专家罗勇 ,回复282或者20181116可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 先上 ...