bio linux 创建_Linux 五种IO模型
网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。刚才说了,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:
第一阶段:等待数据准备 (Waiting for the data to be ready)。
第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。
对于socket流而言:
第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。
第二步:把数据从内核缓冲区复制到应用进程缓冲区。
网络应用需要处理的无非就是两大类问题,网络IO,数据计算。相对于后者,网络IO的延迟,给应用带来的性能瓶颈大于后者。网络IO的模型大致有如下几种:
BIO – 阻塞模式I/O(bloking IO)
NIO – 非阻塞模式I/O(non-blocking IO)
IO Multiplexing - I/O多路复用模型(multiplexing IO)
AIO – 异步I/O模型(asynchronous IO)
SIO - 信号驱动I/OM模型(signal-driven IO)
注:由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model。
三、 IO模型
1. BIO – 阻塞模式I/O
用户进程从发起请求,到最终拿到数据前,一直挂起等待; 数据会由用户进程完成拷贝
'''
举个例子:一个人去 商店买一把菜刀,
他到商店问老板有没有菜刀(发起系统调用)
如果有(表示在内核缓冲区有需要的数据)
老板直接把菜刀给买家(从内核缓冲区拷贝到用户缓冲区)
这个过程买家一直在等待
如果没有,商店老板会向工厂下订单(IO操作,等待数据准备好)
工厂把菜刀运给老板(进入到内核缓冲区)
老板把菜刀给买家(从内核缓冲区拷贝到用户缓冲区)
这个过程买家一直在等待
是同步io
'''
代码示例:
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
data = conn.recv(1024)
if len(data) == 0:break
print(data)
conn.send(data.upper())
except ConnectionResetError as e:
break
conn.close()
# 在服务端开设多进程或者多线程 进程池线程池 其实还是没有解决IO问题
该等的地方还是得等 没有规避
只不过多个人等待的彼此互不干扰
2. NIO – 非阻塞模式I/O
用户进程发起请求,如果数据没有准备好,那么立刻告知用户进程未准备好;此时用户进程可选择继续发起请求、或者先去做其他事情,稍后再回来继续发请求,直到被告知数据准备完毕,可以开始接收为止; 数据会由用户进程完成拷贝
'''
举个例子:一个人去 商店买一把菜刀,
他到商店问老板有没有菜刀(发起系统调用)
老板说没有,在向工厂进货(返回状态)
买家去别地方玩了会,又回来问,菜刀到了么(发起系统调用)
老板说还没有(返回状态)
买家又去玩了会(不断轮询)
最后一次再问,菜刀有了(数据准备好了)
老板把菜刀递给买家(从内核缓冲区拷贝到用户缓冲区)
整个过程轮询+等待:轮询时没有等待,可以做其他事,从内核缓冲区拷贝到用户缓冲区需要等待
是同步io
同一个线程,同一时刻只能监听一个socket,造成浪费,引入io多路复用,同时监听读个socket
'''
代码示例:
"""
要自己实现一个非阻塞IO模型
"""
import socket
import time
server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)
server.setblocking(False)
# 将所有的网络阻塞变为非阻塞
r_list = []
del_list = []
while True:
try:
conn, addr = server.accept()
r_list.append(conn)
except BlockingIOError:
# time.sleep(0.1)
# print('列表的长度:',len(r_list))
# print('做其他事')
for conn in r_list:
try:
data = conn.recv(1024) # 没有消息 报错
if len(data) == 0: # 客户端断开链接
conn.close() # 关闭conn
# 将无用的conn从r_list删除
del_list.append(conn)
continue
conn.send(data.upper())
except BlockingIOError:
continue
except ConnectionResetError:
conn.close()
del_list.append(conn)
# 挥手无用的链接
for conn in del_list:
r_list.remove(conn)
del_list.clear()
# 客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8081))
while True:
client.send(b'hello world')
data = client.recv(1024)
print(data)
3. IO Multiplexing - I/O多路复用模型
类似BIO,只不过找了一个代理,来挂起等待,并能同时监听多个请求; 数据会由用户进程完成拷贝
'''
举个例子:多个人去 一个商店买菜刀,
多个人给老板打电话,说我要买菜刀(发起系统调用)
老板把每个人都记录下来(放到select中)
老板去工厂进货(IO操作)
有货了,再挨个通知买到的人,来取刀(通知/返回可读条件)
买家来到商店等待,老板把到给买家(从内核缓冲区拷贝到用户缓冲区)
多路复用:老板可以同时接受很多请求(select模型最大1024个,epoll模型),
但是老板把到给买家这个过程,还需要等待,
是同步io
强调:
1. 如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。
2. 在多路复用模型中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。
结论: select的优势在于可以处理多个连接,不适用于单个连接
'''
代码示例:
"""
当监管的对象只有一个的时候 其实IO多路复用连阻塞IO都比比不上!!!
但是IO多路复用可以一次性监管很多个对象
server = socket.socket()
conn,addr = server.accept()
监管机制是操作系统本身就有的 如果你想要用该监管机制(select)
需要你导入对应的select模块
"""
import socket
import select
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
server.setblocking(False)
read_list = [server]
while True:
r_list, w_list, x_list = select.select(read_list, [], [])
"""
帮你监管
一旦有人来了 立刻给你返回对应的监管对象
"""
# print(res) # ([], [], [])
# print(server)
# print(r_list)
for i in r_list: #
"""针对不同的对象做不同的处理"""
if i is server:
conn, addr = i.accept()
# 也应该添加到监管的队列中
read_list.append(conn)
else:
res = i.recv(1024)
if len(res) == 0:
i.close()
# 将无效的监管对象 移除
read_list.remove(i)
continue
print(res)
i.send(b'heiheiheiheihei')
# 客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello world')
data = client.recv(1024)
print(data)
IO复用中的三个API(select、poll和epoll)的区别和联系
select,poll,epoll都是IO多路复用的机制,I/O多路复用就是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),
能够通知应用程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,
也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。三者的原型如下所示:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
1.select
select的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),位数组的每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件,所以每次调用select前都需要重新初始化fdset。timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间select的调用步骤如下:
(1)使用copy_from_user从用户空间拷贝fdset到内核空间
(2)注册回调函数__pollwait
(3)遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll)
(4)以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。
(5)__pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll 来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数 据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。
(6)poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。
(7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是 current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout 指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。
(8)把fd_set从内核空间拷贝到用户空间。
总结下select的几大缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
2.poll
bio linux 创建_Linux 五种IO模型相关推荐
- Linux 下的五种 IO 模型
Linux 下的五种 IO 模型 来源:decaywood's Blog 概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2 ...
- 聊聊 Linux 中的五种 IO 模型
聊聊 Linux 中的五种 IO 模型 2016/04/21 · IT技术 · 8 评论 · iO, 同步, 异步, 阻塞, 非阻塞 分享到:0 本文作者: 伯乐在线 - 陶邦仁 .未经作者许可,禁止 ...
- linux下的五种io模型,Linux下的五种IO模型
Java中提供的IO有关的API,在文件处理的时候,其实依赖操作系统层面的IO操作实现的(关于Java对IO的三种封装,可见我的另一篇博客) 开门见山,Linux下的如中IO模型:阻塞IO模型,非阻塞 ...
- Linux五种IO模型性能分析
转载:http://blog.csdn.net/jay900323/article/details/18141217 Linux五种IO模型性能分析 目录(?)[-] 概念理解 Linux下的 ...
- Windows五种IO模型性能分析和Linux五种IO模型性能分析
Windows五种IO模型性能分析和Linux五种IO模型性能分析 http://blog.csdn.net/jay900323/article/details/18141217 http://blo ...
- java基础巩固-宇宙第一AiYWM:为了维持生计,四大基础之OS_Part_2整起~IO们那些事【包括五种IO模型:(BIO、NIO、IO多路复用、信号驱动、AIO);零拷贝、事件处理及并发等模型】
PART0.前情提要: 通常用户进程的一个完整的IO分为两个阶段(IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者!):[操作系统和驱动程序运行在内核空间,应用程序运行在用户空间, ...
- Linux/Unix五种IO模型
文章目录 引入 操作系统的内核态和用户态 文件描述符fd IO操作过程: 阻塞和非阻塞 同步和异步 同步IO和异步IO 五种IO模型 1.(同步)阻塞IO模型 2.(同步)非阻塞IO模型 3.IO多路 ...
- linux 五种IO模型 简介
Linux下主要的IO主要分为:阻塞IO(Blocking IO),非阻塞IO(Non-blocking IO),同步IO(Sync IO)和异步IO(Async IO). 同步:调用端会一直等待服务 ...
- 详解Linux 五种IO模型
原文:https://www.jianshu.com/p/486b0965c296 上一篇 同步.异步.阻塞.非阻塞 已经通俗的讲解了,要理解同步.异步.阻塞与非阻塞重要的两个概念点了,没有看过的,建 ...
- Linux 五种IO模型
想快速了解,看文末总结. 1 概念说明# 在进行解释之前,首先要说明几个概念: 用户空间和内核空间 进程切换 进程的阻塞 文件描述符 缓存 IO 1.1 用户空间与内核空间## 现在操作系统都是采用虚 ...
最新文章
- 应该知道关于Python的随机模型 以及使用范围例子洗牌 特别长 1米
- OC与c混编实现Java的String的hashcode()函数
- 我发起了一个 用 物理服务器 和 .Net 平台 构建云平台 的 .Net 开源项目
- Opencv--获取Mat图像数据的方式
- python3和python2的优劣_python2和python3的区别
- 阶乘末尾连续零的个数
- OpenCV常用函数(三)
- 【ubuntu操作系统】ubuntu系统下第一个C语言程序
- java毕业设计鉴赏_高校科研管理系统
- citp协议服务器,Picturall Octo 媒体服务器
- python编译器哪个最好用_python编写器哪个好用?
- msi z170 网卡 linux,麻雀虽小五脏俱全:msi 微星 发布 Z170I Gaming Pro AC Mini-ITX主板...
- Vue插件element-ui安装时报错error An unexpected error occurred: “https://registry.npmjs.org/element-ui: conn
- 论文参考文献GB/T 7714格式生成
- 物联网威胁监测系统最新发现一款针对IoT设备的RAT远控木马
- 炽热如初 向新而生|ISC2022 HackingClub白帽峰会圆满举办
- 嵌入式linux华清远见考试,嵌入式Linux小测及答案
- C++语法——详解智能指针的概念、实现原理、缺陷
- 18.06.27 POJ百练 4124海贼王之伟大航路
- 软件开发中会使用到的图
热门文章
- CF1047E Region Separation
- ARC094F Normalization
- POJ2676 Sudoku
- vue-router实现根据用户权限显示不同菜单-动态路由
- ES6、7学习笔记(尚硅谷)-2-let和const
- 计算机游戏蜘蛛纸牌如何还原,经典PC纸牌游戏空当接龙、蜘蛛纸牌等登陆iOS/Android...
- 如何在mysql查询结果集中得到记录行号_如何在MySQL查询结果集中得到记录行号...
- win7系统服务器错误404,Win7旗舰版系统下无法打开http://localhost出现404错误如何解决...
- 小程序如何上传代码到服务器,云服务器怎么上传小程序代码
- python json转换为dict的编码问题_python中json和字符编码的转换