[本文内容主要来源: UNIX Network Programming Volume.1 by W. Richard Stevens]
首先我们来看几个socket相关的函数I/O模型
1. Blocking I/O 模型
这个模型是最普通和常见的, 以recvfrom为例. 这个函数在返回之前有两个过程
1). 等待数据到来.
2). 从内核空间copy数据到用户空间.
用图表示就是这样:
在这两个过程完成之前, 这个函数是不会返回的, 整个过程都是blocking的.
2. Nonblocking I/O 模型
当我们把socket设置为nonblocking, 如果内核没有数据, 函数返回时, 返回值为EWOULDBLOCK. 通过fcntl设置文件描述符O_NONBLOCK位.
3. I/O多路模型
上面两个模型是连个极端, 一个是完全blocking, 一个是完全nonblicking的. 对于blocking模型, 缺点就是不容易控制, 对nonblocking模型, 虽然容易控制, 但会增加内核调用次数. I/O多路模型克服了这两个缺点. 通过select函数可以实现I/O多路模型.
4. I/O信号驱动模型.
I/O多路模型尽管可以设置超时, 但是在select没有返回之前还是blocking的. nonblocking模型可以立即返回, 但还是有之后再次调用函数, 中间的时间不好把握. 信号模型可以克服这些缺点, 可以做到当有数据到来时候通知程序, 之后就可以调用recvfrom函数接收数据, 中间没有由于等待过程的blocking, 和决定多久再再次接收数据的过程.
在利用信号I/O程序要做下面三步:
1). 注册SIGIO处理函数;
2). fcntl 设置F_SETOWN;
3). fcntl F_SETFL, O_ASYNC属性, 或者ioctl设置FIOASYNC.
5. 异步IO模型
和信号模型不同的是, 信号模型是内核告诉程序数据准备好了, 可以读取了, 异步模型是数据完成读取之后通知程序.
比较上面五种模型, 前面四种第二过程是相同的, 不同的只是第一过程; 五种中只有异步模型是完全nonblocking的. 我们可以根据程序的需要采用其中的一种或多种模型来设计程序.