上篇文章说了,内核态和用户态。这篇说下和内核态和用户态有关的 网络IO模型。
先来回顾下内核空间和用户空间:
内核空间:内核进程所在区域,主要是由系统级别的代码进行操作,偏向于底层的操作。
用户空间:我们所写的程序,例如JVM进程。可以访问的区域。用户态的进程一般通过向内核发起调用才能完成IO操作。
对于系统的IO操作,都需要从用户空间到内核空间,然后再由内核空间数据拷贝到用户空间。
Unix网络模型分为5种,阻塞式IO模型,非阻塞式IO,IO复用模型,信号驱动式IO模型,异步信号驱动IO模型。参见《UNIX网络编程卷1》
对于前面的4种模型主要区别于内核区的数据准备。下面从内核态和用户态来说下网路IO模型。
阻塞式IO模型
看下面的图,我们的程序发起recvfrom系统调用,然后在内核区的数据准备和内核拷贝数据到用户空间,等到数据拷贝完成后,再返回成功。这整个过程程序都出于等待状态,阻塞中。
非阻塞式IO模型:非阻塞式IO在内核数据准备过程是非阻塞状态,会一直询问内核是否准备完成。这个过程是一个非阻塞状态。
但是在内核阶段会不断的循环recvfrom内核,所以会消耗CPU时间。
IO复用模型:可以说是非阻塞IO模型的升级版,内核区的数据准备是否完成,在非阻塞式IO式有程序主动的进行轮询调用,而在IO复用中,是由内核主动向进程返回可读条件来完成非阻塞的。程序进程有select操作,来监听哪一个socket的数据准备好了。
Java的NIO操作就是基于该模型的。从图中可以看到,整个IO过程一共有两次系统调用,相比阻塞式IO,多了一次系统调用,所以IO复用模型不见得就比阻塞式IO性能更好。但是对于IO复用好处就是在于复用,可以有一个select来控制多个socket连接。
IO信号驱动式模型:该模型是异步的,我们通过建立SIGIO信号处理程序,当第一次发起sigaction系统调用时,内核进程立即返回。应用进程可以继续工作,无需等待或者监听等。相比上面的三个模型,是异步处理结果。当内核区的数据准备好之后,内核会主动的返回SIGIO到信号处理程序,然后应用进程在recvfrom发起系统调用,开始拷贝数据到用户空间,最后拷贝完成,返回成功。但是拷贝的这个过程也是一个阻塞和同步的状态。
总结:上述四种类型,无论哪种在第二阶段数据拷贝过程都是一个阻塞的同步状态。他们的区别就是在内核区的数据准备过程有所处理。下面看异步IO模型,该模型是和上面4种模型完全不一样。
异步IO模型:可以看到异步IO模型,整个过程都是异步的。