文章目录
关于专栏----WebServer二三事
(一) 本文参考 UNIX 网络编程 卷一 第6章 I/O复用,在阅读这篇文章之前应该对 Socket编程的系列函数和连接的建立过程有一定的理解。
(二) 对I/O模式的讨论要建立在操作系统的基础上,相同I/O模式在不同的系统下有不同的实现。比如异步I/O的实现在Linux和window上的实现就存在很大区别。这篇文章讨论的环境为Linux下的I/O模型。
(三) 同步(synchronous)/异步(asynchronous),阻塞(blocking)/非阻塞(non-blocking) 的概念必须以具体的层级下的定义为前提讨论才有可比性,本文对异步和同步采用POSIX中的定义:
- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
- An asynchronous I/O operation does not cause the requesting process to be blocked;
(四) 对于一个网络I/O操作(read为例)通常涉及如下,
两个对象:
- 调用I/O操作的进程(process)或线程(thread)
- 内核(kernel)
两个阶段(两个阻塞过程):
- 等待数据准备 (Waiting for the data to be ready)
- 将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
以上四点是理解I/O模式的关键。
UNIX下可用的5种I/O模式:
I/O模式 | 同步/异步,阻塞/非阻塞 |
---|---|
阻塞式I/O模型 (blocking I/O) | 同步,阻塞 |
非阻塞式I/O模型 (nonblocking I/O) | 同步,非阻塞 |
I/O多路复用模型 (I/O multiplexing) | 同步,非阻塞 |
信号驱动式I/O模型 (signal driven I/O) | 同步,非阻塞 |
异步I/O模型 (asynchronous I/O) | 异步,非阻塞 |
在概述中提到网络I/O的两种阶段,对于一个Socket来说,如果一方要接收另一方的数据,
- 第一阶段 通常需要等待数据从网络中到达,当所有的分组到达是被复制到内核中的某个缓冲区(内核态);
- 第二阶段 用户进程复制内核缓冲区中的对应数据到进程缓冲区(用户态);
而对同步/异步,阻塞和非阻塞的讨论就是基于这两步进行的。
许多的文章都将阻塞和同步,异步和非阻塞混为一谈,将非阻塞等同于异步,认为I/O复用模式(select,poll,epoll)为异步,其实都是错误的,异步I/O只有使用了特殊的API才能实现,以至于在UNIX Network Programming 在将信号驱动I/O和异步I/O比较时,如下写道 :
As of this writing, few systems support POSIX asynchronous I/O. We are not certain, for example, if systems will support it for sockets. Our use of it here is as an example to compare against the signal-driven I/O model.
支持满足POSIX定义的异步I/O的系统还是比较少的,其中Linux下的AIO还不是真正的异步&