网络编程之五种I/O模型

在网络编程中有5中I/O模型 , 今天我们就来聊一聊这5中模型的原理和区别 。
1.阻塞I/O模型 。
阻塞I/O模型通信示意图如下:
网络编程之五种I/O模型文章插图
阻塞I/O模型通信示意图
当用户调用了recvfrom这个系统调用后 , 内核就开始准备数据 。 对于网络I/O来说 , 很多时候数据还没有到达 , 这个时候要等足够的数据到来 。 而在这个时候 , 用户的进程会被阻塞 , 当数据准备好的时候 , 它就会将数据从内核拷贝到用户内存 , 然后返回结果 , 用户进程这时候才会解除阻塞的状态 , 重新运行起来 。 在阻塞I/O模型中 , 进程阻塞挂起不消耗cpu的资源 , 及时响应每个操作 。 适用于并发量小的网络应用开发 。 对于并发量大的应用 , 需要为每一个请求分配一个处理进程 , 系统开销大 。
2.非阻塞I/O模型 。
非阻塞I/O模型通信示意图如下:
网络编程之五种I/O模型文章插图
非阻塞I/O模型通信示意图
在非阻塞I/O模型中 , 当用户进程发出read操作时 , 如果内核中的数据还没有准备好 , 那么它并不会阻塞用户进程 , 而是立刻返回一个error 。 从用户进程角度来讲 , 发起一个read操作 , 并不需要等待 , 而是马上就得到了一个结果 。 当用户进程判断得到一个error后 , 知道内核还没有准备好数据 , 于是再次发送read操作 , 一旦内核准备好了数据并且收到了用户进程的调用 , 他马上就会把数据拷贝到用户内存 , 然后返回 。 在这种模型中 , 用户进程需要不断的询问内核是否准备好 , 消耗cpu的资源 , 适合并发量较小且不需要及时响应的网络应用开发 。
3.多路复用I/O模型 。
多路复用I/O模型示意图如下:
网络编程之五种I/O模型文章插图
多路复用I/O模型通信示意图
【网络编程之五种I/O模型】 在多路复用I/O模型中 , 多个进程的I/O可以注册到一个复用器(Selector)上 , 当用户进程调用这个Selector , 如果Selector监听的所有I/O在内核缓冲区中都没有可读数据 , select调用进程就会被阻塞 , 而当任意I/O在内核缓冲区中有数据时 , select调用就会返回 , 而后select调用进程可以自己或者通知另外的进程再次发起读取I/O , 读取内核中准备好的数据 。
多路复用模型相对于非阻塞模型来说 , 需要2个系统调用(recvfrom和select) , 但是Selector的优势在于一次能够处理多个连接 , 当连接很多的时候优势是很明显的 , 但是单个连接并不能处理的更快 。 多路复用模型适合高并发的服务器开发 。
4.信号驱动I/O模型 。
信号驱动I/O模型通信示意图如下:
网络编程之五种I/O模型文章插图
信号驱动I/O模型示意图
信号驱动模型是指进程向内核注册一个信号处理函数 , 然后用户进程返回不阻塞 , 当内核数据就绪时 , 返回一个信号给进程 , 用户进程便在处理函数中调用I/O读取数据 。 实际上I/O内核拷贝到用户进程的过程还是阻塞的 , 这种模式并没有实现真正的阻塞 , 是一种伪异步 , 实际中并不常用 。
5.异步I/O模型 。
异步I/O模型通信示意图如下:
网络编程之五种I/O模型文章插图
异步I/O通信模型示意图
用户进程发起aio_read操作后 , 给内核传递与read相同的描述符、缓冲区指针、缓冲区大小三个参数及文件偏移 , 告诉内核但整个操作完成时 , 如何通知我们立刻就可以开始去做其他的事情 , 从内核的角度来讲 , 当它收到一个aio_read后 , 首先它会立刻返回 , 所以不会对用户进程产生阻塞 , 内核会准备等待数据准备完成 , 然后将数据拷贝到用户内存 , 当这一切都完成之后 , 内核会给用户进程发送一个信号 , 告诉它aio_read操作完成 。
异步I/O的机制是:告诉内核启动某个操作 , 并让内核在整个操作完成通知我们 , 它实现了真正的异步操作 , 是真正的异步模型 , 适合高性能高并发的应用 。