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. FloatingActionButton(悬浮按钮)使用学习<一>

      FloatingActionButton简称FAB.   一. 对于App或某个页面中是否要使用FloatingActionButton必要性:     FAB代表一个App或一个页面中最主要的操 ...

  2. 【转载】ASP.NET Core 依赖注入

    本文转自:http://www.jessetalk.cn/2017/11/06/di-in-aspnetcore/ 为什么要写这个博客 DI在.NET Core里面被提到了一个非常重要的位置, 这篇文 ...

  3. ppt制作元素采集

    原文链接 https://www.zhihu.com/question/52157612/answer/247501754?utm_source=qq&utm_medium=social 1动 ...

  4. 语音识别(LSTM+CTC)

    完整版请微信关注“大数据技术宅” 序言:语音识别作为人工智能领域重要研究方向,近几年发展迅猛,其中RNN的贡献尤为突出.RNN设计的目的就是让神经网络可以处理序列化的数据.本文笔者将陪同小伙伴们一块儿 ...

  5. Redux,基础

    在学习了React之后, 紧跟着而来的就是Redux了~ 在系统性的学习一个东西的时候, 了解其背景.设计以及解决了什么问题都是非常必要的. 接下来记录的是, 我个人在学习Redux时的一些杂七杂八~ ...

  6. [Python] Python 学习 - 可视化数据操作(一)

    Python 学习 - 可视化数据操作(一) GitHub:https://github.com/liqingwen2015/my_data_view 目录 折线图 散点图 随机漫步 骰子点数概率 文 ...

  7. MySQL 笔记整理(8.a) --事务到底是隔离还是不隔离的?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 8.a) --事务到底是隔离还是不隔离的? 这部分内容不太容易理解,笔者也是进行了多次阅读.因此引用原文: 之前有提到过,如果是在可 ...

  8. GUID获取16位19位22位的唯一字符串

    /// <summary> /// 根据GUID获取16位的唯一字符串 /// </summary> /// <param name=\"guid\" ...

  9. python之编码与解码

    编码 字符串被当作url提交时会被自动进行url编码处理,在python里也有个urllib.urlencode的方法,可以很方便的把字典形式的参数进行url编码.当url地址含有中文或者“/”的时候 ...

  10. 数据结构(java版)学习笔记(三)——线性表之单链表

    单链表的优点: 长度不固定,可以任意增删. 单链表的缺点: 存储密度小,因为每个数据元素,都需要额外存储一个指向下一元素的指针(双链表则需要两个指针). 要访问特定元素,只能从链表头开始,遍历到该元素 ...