五种I/O模型
前面四种属于同步IO模型。
预备知识
I/O的两个步骤:
阻塞的文件描述符称为阻塞I/O;
I/O阻塞执行的系统调用,如果相关事件没有就绪,意味着不能被立即完成,此时就会被操作系统挂起,直到被等待事件就绪。

EWOULDBLOCK错误码。所有的套接字创建的时候默认都是阻塞的,套接字API中,可能被阻塞的系统调用包括accept、send、recv、connect。
非阻塞的文件描述符称为非阻塞I/O;
非阻塞I/O执行的系统调用,不管相关事件是否发生,总是立即返回。往往需要程序员使用循环的方式返回尝试读写文件描述符,这个过程称为轮询。

如果等待的事件没有立即发生,这些系统调用会以出错的形式返回的。其实它不是真正地调用失败,事件未就绪和真正的调用出错都是以出错的形式返回,区分这两个情况的关键在于错误码:
EAGAIN(“再来一次”)/EWOULDBLOCK(“期望阻塞”)。EINPROGRESS(“在处理中”)。显然,非阻塞I/O很容易浪费CPU资源,通常不单独使用,而是和其他I/O通知机制一起使用
信号驱动I/O
可以为目标文件描述符指定宿主进程,这个进程将捕获到SIGIO信号。当内核将该目标文件描述符上的IO事件准备就绪时,会使用SIGIO信号通知应用进程进行I/O操作,然后SIGIO信号的信号处理函数会被触发。我们可以在SIGIO信号处理函数内部对目标文件描述符执行非阻塞I/O操作。

多路复用I/O
应用进程通过I/O复用函数向内核注册一组事件,能够同时等待多个文件描述符的I/O事件就绪,内核通过I/O复用函数将其中就绪的事件通知给应用进程。

Linux上常用的I/O复用函数:select、poll、epoll_wait。
注意:
异步I/O
内核在数据拷贝完成后,通知应用程序(信号驱动是告诉应用程序何时开始拷贝数据)。

同步I/O与异步I/O的区别:
Linux的aio.h头文件中定义了支持异步I/O的函数。
| I/O模型 | 阻塞阶段 |
|---|---|
| 阻塞I/O | 阻塞于读写函数 |
| 非阻塞I/O | 无阻塞阶段 |
| 信号驱动I/O | 无阻塞阶段 |
| 多路复用I/O | 阻塞于I/O复用系统调用,对I/O本身的读写操作是非阻塞的 |
| 异步I/O | 无阻塞阶段 |