Unix网络编程笔记-IO模型
unix系统共有5种I/O模型
-
阻塞式IO
-
非阻塞式IO
-
IO多路复用
-
信号驱动式IO
-
异步IO
一个输入操作通常包括两个不同的阶段:
-
等待数据准备好
-
从内核向进程复制数据
对应一个套接字上的操作,第一步通常涉及数据从网络到达,当所有数据到达时,它被复制到内核的某个缓冲区。第二步就是从内核缓冲区复制到用户进程的缓冲区。
一、阻塞式IO
最流行IO是阻塞式IO,如下图所示,用户进程调用recvfrom,recvfrom系统调用直到数据复制到用户进程缓冲区或发生错误才返回。整段时间用户进程是被阻塞的。
二、非阻塞式IO
进程把一个套接字设置成非阻塞是通知内核:当所有请求的IO操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠。而是返回一个错误。
前三次调用recvfrom都没有返回,因此内核直接返回一个EWOULDBLOCK错误,第四次调用recvfrom时数据已经准备好,然后被复制到应用进程缓冲区。于是recvfrom成功返回。
当一个应用进程对非阻塞描述符循环调用recvfrom时,我们称之为轮询(polling),应用进程持续轮询内核以查看某个操作是否就绪,这样做往往耗费大量CPU时间。这种模型偶尔会用到。
三、IO多路复用
有了IO多路复用(IO multiplexing),我们就可以调用select或poll,阻塞在这两个系统调用中的某一个之上,而不是阻塞在真正的IO系统调用上。
我们阻塞在select,等待数据报套接字变成可读,当select返回套接字可读这一条件是,我们调用recvfrom把数据复制到应用进程缓冲区。
事实上由于使用select复制数据需要两个系统调用而不是之前的一个,似乎还有劣势,其实select的优势在于,我们可以用select在等待多个描述符就绪。
四、信号驱动IO模型
我们也可以用信号,让内核在描述符就绪时发生SIGIO通知我们,这就是信号驱动式IO,如下图
我们首先开启套接字的信号驱动式IO功能,并通过sigaction系统调用安装一个信号处理函数,该系统调用立即返回。进程继续工作。当数据报就绪时,内核为该进程产生一个SIGIO信号,进程可以通过在信号处理函数中调用recvfrom读取数据。也可以通知主循环让他读取数据报。
无论如何处理SIGIO信号,这种模型的优势在于等待数据报到达期间不被阻塞,主循环可以继续执行。
五、异步IO模型
异步IO由POSIX规范定义,一般来说的工作机制是:告诉内核启动某个操作(包括数据从内核复制到进程缓冲区),并让内核在整个操作完成后通知我们。
这一模型与信号驱动IO模型的区别在于,信号驱动IO是内核通知我们何时可以启动一个IO,而异步IO通知我们IO操作何时完成。
我们调用aio_read函数,给内核传递描述符、缓冲区指针、缓冲区大小(同read)和文件偏移(同lseek),并告诉内核在整个操作完成后通知我们。
该系统调用立即返回,而且在等待IO完成期间,进程不会被阻塞。
该信号直到数据被复制到应用进程缓冲区才产生,这一点与信号驱动IO不同。
各种IO模型的比较
前四种模型的主要区别在第一阶段,他们的第二阶段是一样的。
异步IO模型两个阶段都是异步非阻塞的。因此与前面四个模型不同。
POSIX把下面两个定义为:
同步IO操作:导致请求进程阻塞,指定IO操作完成
异步IO操作:不导致请求进程阻塞
从上面的定义来看,前面四种模型都是同步IO模型,因为recvfrom是阻塞的,只有最后一种是异步IO模型
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2017-04-26 python小技巧
2017-04-26 python集合的内建函数
2017-04-26 python字典的内建函数
2017-04-26 python列表的内建函数
2017-04-26 python的字符串内建函数
2017-04-26 python的实用函数