IO网络模型-非阻塞IO

431 阅读2分钟

非阻塞IO (non-blocking IO)

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

image.png

当用户进程发出read操作时, 如果kernel中的数据没有准备好, 那么它并不会block用户进程, 而是立刻返回一个errno. 从用户进程角度讲, 它发起一个read操作后, 不需要等待, 而是马上得到一个结果, 用户进程判断结果是一个errno, 他就知道数据还没有准备好, 于是它可以再次发送read.

一旦kernel中的数据准备好了, 并且又再次收到了用户进程的system call, 那么它马上就将数据拷贝到了用户内存, 然后返回, 所以, 在非阻塞式IO中, 用户进程其实式需要不断的主动询问kernel数据准备好了没有

在非阻塞状态下, recv()接口在被调用后立即返回, 返回值代表了不同的含义

  • recv()返回值大于0, 标识接收数据完毕, 返回值就是接收到的字节数
  • recv()返回0, 表示连接已经正常断开
  • recv()返回-1, 且error等于EAGAIN, 表示recv操作还没执行完成
  • recv()返回-1, 且error不是EAGAIN, 表示recv操作遇到系统错误errno

非阻塞的接口相比于阻塞型接口的显著差异在于, 在被调用之后立即返回, 使用如下的函数可以将某句柄fd设为非阻塞状态

fcntl(fd, F_SETFL, O_NONBLOCK);

只用一个线程, 但能够同事从多个连接中检测数据是否送达, 并且接收数据的模型

image.png

服务器线程可以通过循环调用recv()接口, 可以在单个线程内实现对所有连接的数据接收工作, 但是这个模型很垃圾, 循坏调用就是拉满CPU占用; 而且recv()更多的是检测操作是否完成, 实际上操作系统提供了更好的检测操作是否完成的接口, 比如 select, 可以一次检测多个连接是否活跃