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. ES 04 - 安装Kibana插件(6.6.0版本)

    目录 1 Kibana是什么 2 安装并启动Kibana 2.1 准备安装包 2.2 修改配置文件 2.3 启动Kibana并验证 2.4 关闭Kibana服务 3 Kibana功能测试 3.1 关于 ...

  2. 为啥用ip不可以访问知乎,而百度却可以?

    我们先来ping知乎的域名,然后可以得到响应的服务器的ip 之后我们用浏览器来访问这个ip,结果如下 被拒绝访问了. 而用ip来访问百度,则没啥问题,如图 访问知乎的时候,域名可以访问,ip不可以访问 ...

  3. 浅析JavaScript工厂模式

    这里主要介绍两种工厂模式,第一种“简单工厂模式”,第二种“工厂方法模式” 简单工厂模式 1.定义 由一个工厂对象决定对象创建某一种产品对象的的实例.主要用来创建同一类对象. 2.具体需求 现在有一个登 ...

  4. 谈谈.NET Core中基于Generic Host来实现后台任务

    目录 前言 什么是Generic Host 后台任务示例 控制台形式 消费MQ消息的后台任务 Web形式 部署 IHostedService和BackgroundService的区别 IHostBui ...

  5. springboot情操陶冶-web配置(五)

    本文讲讲mvc的异常处理机制,方便查阅以及编写合理的异常响应方式 入口例子 很简单,根据之前的文章,我们只需要复写WebMvcConfigurer接口的异常添加方法即可,如下 1.创建简单的异常处理类 ...

  6. 【EF】CodeFirst Fluent API使用记录

    我们在使用EF CodeFirst 模式生成数据库的时候进行表的代码映射关系可以采用注解模式和Fluent API模式.这里就是记录一下使用Fluent API进行表关系映射的方法. 注解模式: 回顾 ...

  7. [Go] 并发和并行的区别

    并发和并行的区别:1.并行是让不同的代码片段同时在不同的物理机器上运行,并行的关键是在不同的物理机器上同时运行 2.并发是同时管理很多事情,比如在一个物理机器上进行不停的调度,有些事情可能只做了一半就 ...

  8. Ext中继承知识点

    Ext.define(entend):定义类,单继承 Ext.define(override):定义类的补丁(扩展或重写) Ext.extend:老版本的定义类,单继承 Ext.override:4种 ...

  9. 20190325-HTML框架、audio标签、vedio标签、source标签、HTML表单

    目录 1.HTML框架 frameset:框架标记 frame:框架内文件 iframe:内嵌框架 2.audio标签 src:URL(可以用source标签替代) autoplay:自动播放 pre ...

  10. WGS84地理坐标系下,进行坐标运算

    经纬度坐标本身是不能直接运算的.原因是:经纬度坐标并非是直角坐标系.纬线圈间隔均匀,经线圈越靠近两级越密,如下图: 现在有个需求,已知两点和两点处射线斜率,求交点坐标. 虽然地球整体是个圆,但是局部地 ...