在UNIX下可用的5种I/O模型为:
柱塞I/O模型
非柱塞I/O模型
I/O复用(select和poll)
信号驱动式I/O(SIGIO)
异步I/O
柱塞式I/O模型
最流行的I/O模型是柱塞式I/O模型,默认情况下所有套接字都是用柱塞的,以数据报套接字为例子,如图:
进程调用recvfrom,其系统调用指导数据报到达且被复制到应用进程的缓冲区中或发生错误才返回,最常见的错误是系统调用被信号中断,进程在从调用recvfrom开始到它开始返回的整段时间是被柱塞的,recvfrom成功返回后,应用程序开始处理数据报。
非柱塞式I/O模型
进程把一个套接字设置成非柱塞是在通知内核:当所请求的I/O操作非得把进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误,如图:
前三次调用recvfrom时没有数据返回,因此内核转而立即返回一个EWOULDBLOCK错误,第四次调用recvfrom时,已有数据报准备好,它被复制到应用进程缓冲区,于是recvfrom成功返回,然后接着处理数据。当一个应用程序像这样对一个非柱塞描述符循环调用recvfrom时,我们称之为轮询(poll)。
I/O复用模型
有了I/O复用,我们就可以调用select或poll,柱塞在这两个系统调用中的某一个之上,而不是柱塞在真正的I/O系统调用上如图所示:
我们柱塞于select调用,等待数据包套接字变为可读,当select返回套接字可读这一条件时,我们调用recvfrom把所有数据报复制到应用进程缓冲区
信号驱动式I/O模型
我们也可以用信号,让内核在描述符就绪时发送SIGIO信号通知我们,我们称这种模型为信号驱动式I/O。如图所示:
首先开启套接字的信号驱动式I/O功能,并通过sigaction系统调用安装一个信号处理函数,该系统调用将立即返回,然后进程继续工作,也就是说它没有被阻塞。当数据报准备好读取时,内核就为进程产生一个SIGIO信号,随后既可以在信号处理函数中调用recvfrom读取数据报,并通知主循环,让它读取数据报。
无论如何处理SIGIO信号,这种模式的优势在于等待数据报到达期间进程不被阻塞。主循环可以继续执行,只要等待来自信号处理函数的通知:既可以是数据已准备好呗处理,也可以是数据报已准备好被读取。
异步I/O模型
信号驱动式I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知I/O操作何时完成,如图所示:
调用aio_read函数,给内核传递描述符、缓冲区指针、缓冲区大小和文件偏移,并告诉内核当整个操作完成时如何通知我们。该系统调用立即返回,而且在等待I/O完成期间,我们的进程不被阻塞。