网络 IO 模型

2/21/2022 计算机网络网络编程

基本概念

阻塞与非阻塞

阻塞与非阻塞,用于描述调用者在等待返回结果时的状态。

  • 阻塞:调用者发起请求后,会一直等待返回结果,这期间当前线程会被挂起(阻塞)。
  • 非阻塞:调用者发起请求后,会立刻返回,当前线程也不会阻塞。该调用不会立刻得到结果,调用者需要定时轮询查看处理状态。

同步与异步

而同步与异步,用于描述调用结果的返回机制(或者叫通信机制)。

  • 同步:调用者发起请求后,会一直等待返回结果,即由调用者主动等待这个调用结果。
  • 异步:调用者发起请求后,会立刻返回,但不会立刻得到这个结果,而是由被调者在执行结束后主动通知(如 Callback)调用者。

生活案例说明:说到烧水,我们都是通过热水壶来烧水的。在很久之前,科技还没有这么发达的时候,如果我们要烧水, 需要把水壶放到火炉上,我们通过观察水壶内的水的沸腾程度来判断水有没有烧开。随着科技的发展,现在市面上的水壶都有了提醒功能,当我们把水壶插电之后,水壶水烧开之后会通过声音提醒我们水开了。

对于烧水这件事儿来说,传统水壶的烧水就是同步的,高科技水壶的烧水就是异步的。

用户空间、内核空间、系统调用

操作系统的进程空间可以分为用户空间(User Space)和内核空间(Kernel Space),它们需要不同的执行权限。

  • 大多数系统交互式操作需要在内核空间中运行,比如设备 IO 操作。
  • 我们的应用程序运行在用户空间,是不具备系统级的直接操作权限的。如果应用程序想要访问系统核心功能,必须通过系统调用(System Call)来完成。比如调用recv()函数,会将输入缓冲区中的内容拷贝到用户缓冲区。
  • 系统调用运行在内核空间,是操作系统为应用程序提供的接口。

image.png

五种IO模型

Linux 系统为我们提供五种可用的 IO 模型:阻塞式 IO 模型、非阻塞式 IO 模型、IO 多路复用模型、信号驱动 IO 模型和异步 IO 模型。其中前四种都是同步IO,而最后一种是异步IO

同步阻塞IO模型

Blocking IO:应用进程从发起 IO 系统调用,至内核返回成功标识,这整个期间是处于阻塞状态的。

image.png

在Java程序中,使用Socket 套接字来进行网络编程;

Socket 中文翻译为套接字,是计算机网络中进程间进行双向通信的端点的抽象。一个 Socket 代表了网络通信的一端,是由操作系统提供的进程间通信机制。

要想实现网络通信,至少需要一对 Socket,其中一个运行在客户端,称之为 Client Socket;另一个运行在服务器端,称之为 Server Socket。

Socket 之间的连接过程可以分为三个步骤:(1)服务器监听;(2)客户端连接;(3)连接确认。

ServerSocket server = new ServerSocket(6666); // 监听指定端口
Socket sock = server.accept();

如果没有客户端连接进来,accept()方法会阻塞并一直等待。如果有多个客户端同时连接进来,ServerSocket会把连接扔到队列里,然后一个一个处理。对于Java程序而言,只需要通过循环不断调用accept()就可以获取新的连接。

非阻塞IO模型

Non-Blocking:应用进程可以将 Socket 设置为非阻塞,这样应用进程在发起 IO 系统调用后,会立刻返回。应用进程可以轮询的发起 IO 系统调用,直到内核返回成功标识。

image.png

在 Java NIO(自Java 1.4以来) 就是一种同步非阻塞模型。

NIO是面向==缓冲区==或者==面向块编程==的。数据读取到一个它稍后处理的缓冲区,需要向缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络。

TODO:《Java NIO 的使用》

IO多路复用模型

IO Multiplexin:可以将多个应用进程的 Socket 注册到一个 Select(多路复用器)上,然后使用一个进程来监听该 Select(该操作会阻塞),Select 会监听所有注册进来的 Socket。只要有一个 Socket 的数据准备好,就会返回该Socket。再由应用进程发起 IO 系统调用,来完成数据读取。

image.png

多路复用模型在一些地方也称为是事件驱动IO模型;IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。

通过NIO实现的Reactor模式即是I/O多路复用模型的实现

TODO:《什么是Reactor模式》

信号驱动 IO 模型

Signal Driven IO:可以为 Socket 开启信号驱动 IO 功能,应用进程需向内核注册一个信号处理程序,该操作并立即返回。当内核中有数据准备好,会发送一个信号给应用进程,应用进程便可以在信号处理程序中发起 IO 系统调用,来完成数据读取了。

image.png

系统注册了ISGIO信号处理函数,并且启动了信号驱动式IO后,就可以继续执行程序了,等到数据报准备好之后,内核会发送一个SIGIO信号给应用进程,然后应用进程在信号处理函数中调用recvfrom读取数据报。

这种模型在内核等待数据报达到期间进程不会被阻塞,可以继续执行

异步IO模型

Asynchronous IO:应用进程发起 IO 系统调用后,会立即返回。当内核中数据完全准备后,并且也复制到了用户空间,会产生一个信号来通知应用进程。

image.png

步IO模型才是最理想的IO模型,在异步IO模型中,当用户线程发起read操作之后,立刻就可以开始去做其它的事。注意,异步IO是需要操作系统的底层支持,在Java 7中,提供了Asynchronous IO。

通过AIO实现的Proactor模式即是异步I/O模型的实现

Last Updated: 2/21/2022, 9:16:22 PM