linux / unix下的5种I/O模型

	一个输入操作通常包括两个阶段:
		(1)等待数据准备好
		(2)从内核向进程复制数据
Key:对于一个套接字上输入操作
	第1步:等待数据从网络中到达,当等待分组到达时,会被拷贝到内核中某个缓冲区
	第2步:将数据从内核缓冲区中取出拷贝到应用进程的缓冲区

5种I/O模型的概览如下图:
linux / unix下的5种I/O模型

  1. 阻塞I/O(一般默认情况下都是阻塞I/O)
    linux / unix下的5种I/O模型
    应用进程被阻塞,一直等待内核将数据拷贝到应用进程的缓冲区才返回。
    应用阻塞的过程中,其它应用进程还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其它应用进程还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率效率会比较高。
ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,
 				struct sockaddr *from,socket_t *fromlen); 
参数: 
socketfd:	套接字的描述符
buf:		指向需要保存接收数据的应用进程的缓冲区
len:		接收缓冲区的字节长度
flags:		提供了一种改变套接字默认行为的方式,设定为0表示默认行为。
from:		被声明为一个指向sockaddr结构的指针,当recvfrom()返回成功后,
			将本次接收到的数据来源地址写入from指针指向的结构中
fromlen:	指明地址结构的长度
  1. 非阻塞I/O

linux / unix下的5种I/O模型
设置为非阻塞是在通知内核,当所有的请求的I/O操作非得将本进程投入睡眠(阻塞态)才能完成时,不要将其变为睡眠态,而是返回一个错误码。
进程反复的调用recvfrom()函数来获取数据是否已经准备就绪,就是一个轮询(polling)的过程。也正是这个过程导致cpu不断的工作,耗费cpu的大量时间,则cpu的利用率比较低。

  1. I/O复用
    linux / unix下的5种I/O模型
    将多个socket的描述符fd传递给select,阻塞于select调用,而不是真正的系统调用,之后等待数据报接口变为可读。顺序监测fd集合,只要存在一个fd就绪,那么就返回。epoll进行了改进,对fd的数量不受限制,因为是用链表存储的。

    由于可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。

  2. 信号驱动I/O
    linux / unix下的5种I/O模型
    首先开启套接口的信号驱动I/O功能,并通过sigaction系统调用安装一个信号处理函数,该系统调用立即返回,应用进程不会阻塞,可以继续工作,之后等待内核发送信号通知。
    此种方式要比非阻塞I/O时cpu的利用率更高

  3. 异步I/O
    linux / unix下的5种I/O模型
    工作机制:告知内核启动某个操作,并让内核在整个操作(包括data从内核拷贝到应用进程的缓冲区)完成后再通知。

异步I/O和信号驱动I/O的区别:
信号驱动I/O是由内核通知何是启动一个I/O操作
异步I/O是由内核通知I/O操作何时完成。