Linux 环境下 网络IO模型
本文讨论的背景是Linux环境下的network IO。
IO发生时涉及的对象和步骤:
对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会等待内核经历两个阶段:
1 内核数据准备 (Waiting for the data to be ready)
2 内核把数据从内核空间,拷贝到用户空间中 (Copying the data from the kernel to the process)
记住这两点很重要,因为这些IO Model的区别就是在两个阶段上各有不同的情况。
Linux环境下的network IO划分:异步IO类 、和同步IO类
一、异步IO模型分类
. 阻塞IO
. 非阻塞IO
. IO多路复用(监听多个连接)
. 异步IO
1、阻塞型IO:

当用户进程调用了recvfrom这个系统调用,
阶段1:
kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。
阶段2:
当kernel一直等到数据准备好了,它就会将数据从kernel空间中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
所以,blocking IO的特点就是在IO执行的两个阶段都被block了。
2、非阻塞IO
inux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子。

总结:内核准备数据阶段 非阻塞,内核准备好数据把数据从内核空间发送到用户空间阶段阻塞;
优:程序在内核准备数据阶段 非阻塞,可以去做一些别的事情,定期发送系统调用向内核索要数据;
劣:程序在内核准备数据阶段 不断向内核发起系统调用 浪费系统资源
import time
import socket
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sk.setsockopt
sk.bind(('127.0.0.1',6667))
sk.listen(5)
sk.setblocking(False)
while True:
try:
print ('waiting client connection .......')
connection,address = sk.accept() # 进程主动轮询
print("+++",address)
client_messge = connection.recv(1024)
print(str(client_messge,'utf8'))
connection.close()
except Exception as e:
print (e)
time.sleep(4) #############################client import time
import socket
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) while True:
sk.connect(('127.0.0.1',6667))
print("hello")
sk.sendall(bytes("hello","utf8"))
time.sleep(2)
break
3、IO多路复用型(监听多个连接,实现并发现象)
IO multiplexing这个词可能有点陌生,但是如果我说select,epoll,大概就都能明白了。有些地方也称这种IO方式为event driven IO。我们都知道,select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程;

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上,还更差一些。因为这里需要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。但是,用select的优势在于它可以同时处理多个connection。(多说一句。所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
在IO multiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。
注意1:select函数返回结果中如果有文件可读了,那么进程就可以通过调用accept()或recv()来让kernel将位于内核中准备到的数据copy到用户区。
注意2: select的优势在于可以处理多个连接,不适用于单个连接
总结:阻塞型IO是自己发起系统调用,等待内核准备数据、等待内核把数据copy到用户空间,
区别:它与IO多路复用型select的区别是,IO多路复用型IO 是
(1)select想发起系统调用 等待内核准备好了数据。(等待。。)
(2)内核准备好了数据,给select发送数据发来信息的信号。
(3)程序在向内核发起系统调用。
(4)内核把数据送到用户空间;
*重点
conn,addr=iphon.accept(): 等待客户端连接;(默认情况下,来了一个客户端连接后,就会退出,如果需要循环连接就要用while TURE)
data=conn.recv(1024): 一个conn就是一个客户端连接服务端建立的 通信通道
IO多路复用实现机制
1、IO多路复用selec机制
通过selec.select()实现并发:
selec.select([需要监听的套接字列表][输出][错误输出])方法, 需要传入三个列表参数,代替 sock.accpet()方法等待内核空间中有数据到来;
第一个列表(监听的套接字,可以是服务端创建的 socket对象,和客户端连接服务端产生的 conn套接字对象)
返回结果:
监控列表中哪个套接字对象发生变化,就返回那个套接字对象。
import socket
import select
sk=socket.socket() sk.bind(("127.0.0.1",8801))
print(sk)
sk.listen(5) #sock是服务端创建的套接字 conn是某1客户端连接sock产生的套接字 注意啊!!
#select.select()可以监听多个套接字对象可以是服务端创建sock,和客户端连接过来使用的套接字;
# 其中哪个套接字的数据到了 内核空间 ,就返回那个有变化的套接字!
#r输入 w输出 e 错误
r,w,e=select.select([sk,],[],[]) #select.select([sk,],[],[] 代替socket.accpet()等待内核空间的数据到来
print(r) #如果有客户发来数据 select.select()返回 sk 套接字 for obj in r:
conn,addr=obj.accept()
print(conn,addr)
2、IO多路复用poll机制
select机制的过渡阶段产物(jin)
3、IO多路复用epoll机制
代码:
#***********************server.py
import socket
import select
sk=socket.socket()
sk.bind(("127.0.0.1",8801))
sk.listen(5)
inputs=[sk,]
while True:
r,w,e=select.select(inputs,[],[],5)
print(len(r)) for obj in r:
if obj==sk:
conn,add=obj.accept()
print(conn)
inputs.append(conn)
else:
data_byte=obj.recv(1024)
print(str(data_byte,'utf8'))
inp=input('回答%s号客户>>>'%inputs.index(obj))
obj.sendall(bytes(inp,'utf8')) print('>>',r) #***********************client.py import socket
sk=socket.socket()
sk.connect(('127.0.0.1',8801)) while True:
inp=input(">>>>")
sk.sendall(bytes(inp,"utf8"))
data=sk.recv(1024)
print(str(data,'utf8')) select函数阻塞程序运行,监控inputs中的套接字,当其中有套接字满足可读的条件(第一个参数为可读,如果是第二个参数则为可写),则把这个套接字返回给rs,然后程序继续运行。至于套接字怎么才算可读呢?搜索可知,当套接字缓冲区大于1byte时,就被标记为可读。也就是说,当套接字收到客户端发来的数据,就变成可读,然后select就会把这个套接字取出来,进入下一步程序。
4、Asynchronous I/O(异步IO)
总结:内核准备数据阶段 非阻塞,内核准备好数据把数据从内核空间发送到用户空间阶段 非阻塞;
优:程序在内核准备数据阶段 和 内核准备数据阶段 程序都处在非阻塞状态,大大提升IO传输 性能
劣:基于异步IO的程序开发复杂度高;

本文出处:http://www.cnblogs.com/yuanchenqi/articles/6755717.html(苑浩博客)
Linux 环境下 网络IO模型的更多相关文章
- windows和linux环境下keras的模型框架可视化
1.简介 keras提供了模型可视化模块,下面讲解下安装教程和简易教程. 2.安装教程 2.1windows环境下的安装 2.1.1安装指定模块 pip install pydot-ng pip in ...
- Linux环境下网络编程杂谈《转》
今天我们说说“Pre-网络编程”.内容比较杂,但都是在做网络应用程序开发过程中经常要遇到的问题. 一.大端.小端和网络字节序 小端字节序:little-endian,将低字节存放在内存的起始地址: 大 ...
- 从操作系统层面理解Linux下的网络IO模型
I/O( INPUT OUTPUT),包括文件I/O.网络I/O. 计算机世界里的速度鄙视: 内存读数据:纳秒级别. 千兆网卡读数据:微妙级别.1微秒=1000纳秒,网卡比内存慢了千倍. 磁盘读数据: ...
- Socket-IO 系列(一)Linux 网络 IO 模型
Socket-IO 系列(一)Linux 网络 IO 模型 一.基本概念 在正式开始讲 Linux IO 模型前,先介绍 5 个基本概念. 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器, ...
- Linux环境下的network IO
同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. ...
- linux下的IO模型---学习笔记
1.linux文件系统和缓存 文件系统接口 文件系统-一种把数据组织成文件和目录的存储方式,提供了基于文件的存取接口,并通过文件权限控制访问. 存储层次 文件系统缓存 主存(通常时DRAM)的一块区域 ...
- 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...
- 转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
此文章为转载,如有侵权,请联系本人.转载出处,http://blog.chinaunix.net/uid-28458801-id-4464639.html 同步(synchronous) IO和异步( ...
- 网络IO模型
同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...
随机推荐
- 虚拟现实外包公司—北京动点飞扬软件承接VR/AR软件、游戏外包
欢迎通过以下方式联系北京动点飞扬软件外包业务咨询QQ:372900288 (全天在线) 咨询邮箱:SLteam@vip.qq.com 同时我们还承接 HTML5外包. kinect外包.Uni ...
- python网络编程基础之socket粘包现象
粘包现象两种 登陆 #服务端import json import socket server=socket.socket()#创建socket对象 ip_port=('127.0.0.1',8001) ...
- 深入JVM对象引用
在jdk 1.2以前,创建的对象只有处在可触及(reachaable)状态下,才能被程序所以使用,垃圾回收器一旦发现无用对象,便会对其进行回收.但是,在某些情况下,我们希望有些对象不需要立刻回收或者说 ...
- 【转】构造自己的DIB类
ZC: 搜索"DIB_HEADER_MARKER"时,看到的这个文章 http://blog.csdn.net/yyyuhan/article/details/2026652 ...
- Flask-SQLAlchemy基本操作
db.session.rollback() 回滚"""Role.query.get(2) get查询接收的参数为主键,如果不存在,返回空 >>> Use ...
- ubuntu18+gtx1060 +cuda9+cudnn-v7+opencv3.1.0 配置深度学习环境
将笔记本的ubuntu系统更新到18版本后重新配置深度学习环境,在此记载方便日后参考 具体配置为 Ubuntu18.04+gtx1060+opencv-3.1 第1步 安装依赖包 sudo apt-g ...
- Codeforces 101572 D - Distinctive Character
D - Distinctive Character 思路:bfs 使最大的匹配数最小,转换一下,就是使最小的不匹配数最大,用bfs找最大的距离 代码: #pragma GCC optimize(2) ...
- L1 正则为什么会使参数偏向稀疏
2018-12-09 22:18:43 假设费用函数 L 与某个参数 x 的关系如图所示: 则最优的 x 在绿点处,x 非零. 现在施加 L2 regularization,新的费用函数()如图中蓝线 ...
- legend2---开发日志1(legend的数据库整体设计思路是什么)
legend2---开发日志1(legend的数据库整体设计思路是什么) 一.总结 一句话总结:不同种类的物品分不同的表放,不放到一个物品表里,取所有物品时一个个表的取就好了 不同种类的物品分不同的表 ...
- Being a Good Boy in Spring Festival HDU - 1850
桌子上有M堆扑克牌:每堆牌的数量分别为Ni(i=1…M):两人轮流进行:每走一步可以任意选择一堆并取走其中的任意张牌:桌子上的扑克全部取光,则游戏结束:最后一次取牌的人为胜者. 现在我们不想研究到底先 ...