Unix下的五种I/O网络模型分别为:
(1)阻塞式I/O
(2)非阻塞式I/O
(3)I/O多路复用
(4)信号驱动式I/O
(5)异步I/O
为什么会有这5种I/O模型?
明确两点:
-
网络I/O会涉及到两个系统对象:
(1) 用户空间 调用的IO进程/线程
;
(2) 内核空间 的内核系统
; -
I/O操作会经历两个阶段:
(1) 等待数据准备就绪
;
(2) 将数据从内核拷贝到进程或者线程
;上述两个步骤是针对read操作,如果是write,则I/O的两个阶段为:
(1) 等待写缓冲区可写;
(2) 将待写入的数据从进程或者线程拷贝到内核;针对在I/O操作的这两个阶段是否会发生阻塞,将I/O操作划分为5种模型。
“真正的I/O操作”:
将数据从内核空间拷贝到用户空间(recvfrom)和 将数据从用户空间拷贝到内核空间(sendto) 才是真正的I/O操作,等待数据就绪实际上并不是I/O操作,它只是在判断I/O是否可操作。
因此判断一个I/O模型是同步还是异步的标准就是 判断I/O操作时(recvfrom、sendto)是否将用户进程阻塞住。
同步与异步、阻塞与非阻塞:
同步、异步 描述的两个系统系统对象的关系(一个对象在操作I/O时是否会阻塞住另一个对象的执行,或者说一个对象是否会在另一个对象操作I/O时阻塞直至其操作完毕);
阻塞、非阻塞描述的是一个I/O的状态。
1. 阻塞式I/O:

阻塞式IO在【等待数据】和【拷贝数据】这两步都是阻塞的。
2. 非阻塞式I/O:
非阻塞式IO在【等待数据】这一步是非阻塞的,在【拷贝数据】这一步是阻塞的,所以“非阻塞式IO”是一个伪的非阻塞形式,它在从内核将数据拷贝到用户空间的这一步中还是阻塞式操作的,异步IO才是真正的非阻塞。
3. I/O多路复用:
进程阻塞在select函数上等待数据可读,当数据就绪后select返回,应用进程根据select返回的就绪fd的类型(可读、可写、出错)去调用对应的函数拷贝数据,拷贝数据的过程依然是阻塞式的。
4. 信号驱动式I/O:
进程调用sigaction函数注册信号回调函数后就返回,因此在等待数据就绪这一步是非阻塞式的;当数据就绪后,内核调用之前注册号的信号回调函数,进程开始拷贝数据,这一步是阻塞的。
5. 异步I/O:
【等待数据就绪】与【拷贝数据】这两步都是非阻塞的,当数据就绪后内核会自动将数据从内核空间拷贝的用户空间,拷贝完成后向用户进程发送一个信号,通知用户进程来读取数据。
5种I/O模型的比较:
前4种模型都是 同步I/O,因为 真正的I/O操作(recvfrom、sendto)将阻塞进程;
只有异步I/O模型与POSIX定义的异步I/O相匹配。