网络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模型相关推荐

  1. Linux 下的五种 IO 模型

    Linux 下的五种 IO 模型 来源:decaywood's Blog 概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2 ...

  2. 聊聊 Linux 中的五种 IO 模型

    聊聊 Linux 中的五种 IO 模型 2016/04/21 · IT技术 · 8 评论 · iO, 同步, 异步, 阻塞, 非阻塞 分享到:0 本文作者: 伯乐在线 - 陶邦仁 .未经作者许可,禁止 ...

  3. linux下的五种io模型,Linux下的五种IO模型

    Java中提供的IO有关的API,在文件处理的时候,其实依赖操作系统层面的IO操作实现的(关于Java对IO的三种封装,可见我的另一篇博客) 开门见山,Linux下的如中IO模型:阻塞IO模型,非阻塞 ...

  4. Linux五种IO模型性能分析

    转载:http://blog.csdn.net/jay900323/article/details/18141217     Linux五种IO模型性能分析 目录(?)[-] 概念理解 Linux下的 ...

  5. Windows五种IO模型性能分析和Linux五种IO模型性能分析

    Windows五种IO模型性能分析和Linux五种IO模型性能分析 http://blog.csdn.net/jay900323/article/details/18141217 http://blo ...

  6. java基础巩固-宇宙第一AiYWM:为了维持生计,四大基础之OS_Part_2整起~IO们那些事【包括五种IO模型:(BIO、NIO、IO多路复用、信号驱动、AIO);零拷贝、事件处理及并发等模型】

    PART0.前情提要: 通常用户进程的一个完整的IO分为两个阶段(IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者!):[操作系统和驱动程序运行在内核空间,应用程序运行在用户空间, ...

  7. Linux/Unix五种IO模型

    文章目录 引入 操作系统的内核态和用户态 文件描述符fd IO操作过程: 阻塞和非阻塞 同步和异步 同步IO和异步IO 五种IO模型 1.(同步)阻塞IO模型 2.(同步)非阻塞IO模型 3.IO多路 ...

  8. linux 五种IO模型 简介

    Linux下主要的IO主要分为:阻塞IO(Blocking IO),非阻塞IO(Non-blocking IO),同步IO(Sync IO)和异步IO(Async IO). 同步:调用端会一直等待服务 ...

  9. 详解Linux 五种IO模型

    原文:https://www.jianshu.com/p/486b0965c296 上一篇 同步.异步.阻塞.非阻塞 已经通俗的讲解了,要理解同步.异步.阻塞与非阻塞重要的两个概念点了,没有看过的,建 ...

  10. Linux 五种IO模型

    想快速了解,看文末总结. 1 概念说明# 在进行解释之前,首先要说明几个概念: 用户空间和内核空间 进程切换 进程的阻塞 文件描述符 缓存 IO 1.1 用户空间与内核空间## 现在操作系统都是采用虚 ...

最新文章

  1. 应该知道关于Python的随机模型 以及使用范围例子洗牌 特别长 1米
  2. OC与c混编实现Java的String的hashcode()函数
  3. 我发起了一个 用 物理服务器 和 .Net 平台 构建云平台 的 .Net 开源项目
  4. Opencv--获取Mat图像数据的方式
  5. python3和python2的优劣_python2和python3的区别
  6. 阶乘末尾连续零的个数
  7. OpenCV常用函数(三)
  8. 【ubuntu操作系统】ubuntu系统下第一个C语言程序
  9. java毕业设计鉴赏_高校科研管理系统
  10. citp协议服务器,Picturall Octo 媒体服务器
  11. python编译器哪个最好用_python编写器哪个好用?
  12. msi z170 网卡 linux,麻雀虽小五脏俱全:msi 微星 发布 Z170I Gaming Pro AC Mini-ITX主板...
  13. Vue插件element-ui安装时报错error An unexpected error occurred: “https://registry.npmjs.org/element-ui: conn
  14. 论文参考文献GB/T 7714格式生成
  15. 物联网威胁监测系统最新发现一款针对IoT设备的RAT远控木马
  16. 炽热如初 向新而生|ISC2022 HackingClub白帽峰会圆满举办
  17. 嵌入式linux华清远见考试,嵌入式Linux小测及答案
  18. C++语法——详解智能指针的概念、实现原理、缺陷
  19. 18.06.27 POJ百练 4124海贼王之伟大航路
  20. 软件开发中会使用到的图

热门文章

  1. CF1047E Region Separation
  2. ARC094F Normalization
  3. POJ2676 Sudoku
  4. vue-router实现根据用户权限显示不同菜单-动态路由
  5. ES6、7学习笔记(尚硅谷)-2-let和const
  6. 计算机游戏蜘蛛纸牌如何还原,经典PC纸牌游戏空当接龙、蜘蛛纸牌等登陆iOS/Android...
  7. 如何在mysql查询结果集中得到记录行号_如何在MySQL查询结果集中得到记录行号...
  8. win7系统服务器错误404,Win7旗舰版系统下无法打开http://localhost出现404错误如何解决...
  9. 小程序如何上传代码到服务器,云服务器怎么上传小程序代码
  10. python json转换为dict的编码问题_python中json和字符编码的转换