java网络中的IO模型

学习IO模型需要的基础

文件描述符

Linux 的内核将所有外部设备都看做一个文件来操作,对一个文件的读写操作会调用内核提供的系统命令(api),返回一个file descriptor(fd,文件描述符)。而对一个socket的读写也会有响应的描述符,称为socket fd(socket文件描述符),描述符就是一个数字,指向内核中的一个结构体(文件路径,数据区等一些属性)。

用户空间和内核空间

为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分

  • 一部分为内核空间
  • 一部分为用户空间

I/O运行过程

以read为例:

image-20221127200400663

通过上图的操作流程可以发现,应用程序调用read方法时,是需要等待的,有两个过程:

  • 从内核空间中找数据
  • 将内核空间的数据拷贝到用户空间中

阻塞IO模型(BIO)

应用程序发起系统调用到数据包被复制到应用程序的缓冲区中或者发生错误返回,在此期间是一直等待的。

image-20221127200735955

优点:开发简单,容易入门。在阻塞等待期间,用户线程挂起,在挂起期间不会占用 CPU 资源

缺点:一个线程维护一个 IO ,不适合大并发,在并发量大的时候需要创建大量的线程来维护网络连接,内存、线程开销非常大

非阻塞IO模型(NIO)

进程反复进行系统调用,如果数据没有准备好,则返回一个EAGAIN。一般都对非阻塞I/O模型进行轮询检查这个状态,看内核是不是有数据到来。

image-20221127201120197

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

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

同步非阻塞 IO 优点:每次发起 IO 调用,在内核等待数据的过程中可以立即返回,用户线程不会阻塞,实时性好

同步非阻塞 IO 缺点:多个线程不断轮询内核是否有数据,占用大量 CPU 资源,效率不高。一般 Web 服务器不会采用此模式

IO多路复用模型

它的基本原理就是 select/epoll 这个 function会不断的轮询所负责的所有 socket,当某个 socket 有数据到达了,就通知用户进程。

image-20221127201540663

IO多路复用的流程

(1)当用户进程调用了select,那么整个进程会被block;

(2)而同时,kernel会“监视”所有select负责的socket;

(3)当任何一个socket中的数据准备好了,select就会返回;

(4)这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程(空间)。

所以,I/O 多路复用的特点是通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符其中的任意一个进入读就绪状态,select()函数就可以返回

异步模型(AIO)

用户进程发起 read 操作之后,立刻就可以开始去做其它的事。而另一方面,从 kernel的角度,当它收到一个 asynchronous read 之后,首先它会立刻返回,所以不会对用户进程产生任何 block。然后,kernel 会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel 会给用户进程发送一个 signal,告诉它 read 操作完成了。


java网络中的IO模型
http://example.com/2022/11/27/java网络中的IO模型/
作者
zlw
发布于
2022年11月27日
许可协议