linux网络IO模型——阻塞非阻塞和同步异步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux网络IO模型——阻塞非阻塞和同步异步相关的知识,希望对你有一定的参考价值。

最近几天在学习nginx的时候了解了一下linux网络IO模型,在此谈谈我自己的理解,如有错误请多多指教。本文参考书籍Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking ”,6.2节“I/O Models ”。

Linux网络IO请求数据分为两段:

  1.数据准备

  2.将数据从内核拷贝到进程空间

其实,阻塞、非阻塞和同步、异步的不同就在于这两个阶段的不同。

同步和异步关注的是消息通信机制

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态

阻塞(blocking IO)

  linux中,默认情况下socket都是阻塞的,大致过程如下:

  技术分享

如图,进程发起recvform后,内核进行第一阶段准备数据,但是很多时候数据开始时不会全部到达,对于进程来说就处于blocking状态,数据准备好后,内核将数据拷贝到进程空间,拷贝完毕后kernel返回结果,进程结束阻塞状态。即blocking IO两个阶段全部处于blocking状态。

 

非阻塞(non-blocking IO)

  linux中我们可以设置socket为non-blocking,当发出的IO请求没有完成时,不是把进程转为睡眠态,而是返回一个error。

  技术分享

如图所示,当用户发起read时,数据若没有准备好,kernel会立即返回一个error,不需要等待。当进程收到error(EWOULDBLOCK)后,知道数据还没有准备好,之后继续发送read请求。kernel会继续收到进程的system call请求,直到数据准备好,内核会将数据拷贝到用户进程空间。这种模型需要进程不间断的发起system call请求,这会造成cpu时间的浪费。

 

IO复用(IO Multiplexing)

  IO复用多数人所知的是select,poll。select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/poll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。大致过程如下:

  技术分享

当用户进程调用了select,整个进程就会被阻塞。同时内核会轮询查看所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用system call,将数据从kernel拷贝到用户进程空间。

这个模型和blocking IO相比,并没有多大的优势,甚至有时候还不如blocking IO。select/poll的优势是可以同时处理多个connection,并不是单个connection处理得更快。

 

异步IO(Asynchronous I/O Model)

  技术分享

用户进程发起system call调用之后,就可以去做其他事了。从kernel的角度,当它收到一个aio_read之后,它会立刻返回,所以不会对用户进程产生blocking。kernel会等待数据准备完成,然后将数据拷贝到用户内存,拷贝完成后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

 

blocking和non-blocking的区别:

  blocking会一直阻塞进程直到操作完成,non-blocking在内核准备数据的时候会立即返回。

 

同步synchronous I/O 和异步asynchronous I/O的区别

  synchronous io在请求数据的过程中存在阻塞,asynchronous io在请求数据的过程中不存在阻塞。

各种IO模型比较:

  技术分享

如图,blocking,non-blocking,I/O multiplexing均属于synchronous IO。

以上是关于linux网络IO模型——阻塞非阻塞和同步异步的主要内容,如果未能解决你的问题,请参考以下文章

透彻Linux(Unix)五种IO模型

网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

linux5种IO模型以及同步异步,阻塞非阻塞

Linux IO模型(同步异步阻塞非阻塞等)的几篇好文章

IO模型对比:同步异步阻塞非阻塞

同步阻塞同步非阻塞异步阻塞异步非阻塞