IO从概念上来说,总共有5种:

(1)阻塞IO (blocking I/O)

(2)非阻塞IO (nonblocking I/O)

(3)IO多路复用 (I/O multiplexing (select and poll))

(4)事件驱动IO (signal driven I/O (SIGIO))(Unix)

(5)异步IO (asynchronous I/O (the POSIX aio_functions))

不管文件IO还是网络socket的IO,其读写都需要经过两个阶段:

(1) wait for data(准备数据到内核的缓冲区)

(2) copy data from kernel to user (从内核缓冲区拷贝到用户空间)

阻塞 IO(blocking IO)

在 linux 中,默认情况下所有的 socket 都是 blocking。

Untitled

blocking IO 的特点就是在 IO 执行的两个阶段(等待数据和拷贝数据两个阶段)都被 block 了。

非阻塞 IO(non-blocking IO)

Linux 下,可以通过设置 socket 使其变为 non-blocking。当对一个 non-blocking socket 执行读操作时,流程是这个样子

Untitled

从图中可以看出,当用户进程发出 read 操作时,如果 kernel 中的数据还没有准备好,那 么它并不会 block 用户进程,而是立刻返回一个 error。

从用户进程角度讲 ,它发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。

使用非阻塞的接收方式,服务器线程可以通过循环调用 recv()接口,可以在单个线程内实现对所有连接的数据接收工作。但是上述模型绝不被推荐。因为循环调用 recv()将大幅度推高 CPU 占用率 ;此外,在这个方案中 recv()更多的是起到检测“操作是否完成”的作用,实际上操作系统提供了更为高效的检测“操作是否完成“作用的接口,例如 select()多路复用模式, 可以一次检测多个连接是否活跃。

IO多路复用(IO multiplexing)