【Netty】NIO 简介 ( NIO 模型 | NIO 三大组件 | 选择器 Selector | 通道 Channel | 缓冲区 Buffer | NIO 组件分配 | 缓冲区示例 )

2023-03-27 20:36:17 浏览数 (2)

文章目录
  • I . NIO 模型
  • II . NIO 三大组件交互流程
  • III . NIO 缓冲区
  • IV . NIO 与 BIO 对比
  • V . NIO 线程分配
  • VI . 缓冲区 ( Buffer ) 示例

I . NIO 模型

NIO 简介 :

① NIO 概念 : NIO 全称为 Non-Blocking IO , 是非阻塞 IO , 与 BIO ( Blocking IO / 阻塞 IO ) 相对应 ;

② NIO 相对于 BIO 的改进 : NIO 在 BIO 的基础上 , 增加了 IO 的性能 ;

③ NIO 模型特点 : NIO 是同步非阻塞模型 , BIO 是同步阻塞模型 ;

④ NIO API 位置 : 在 Java 中 , NIO 定义在 java.nio 包中 ;

⑤ NIO 三大组件 :

  • 通道 Channel : 相当于 BIO 中的 Socket , 用于传输数据 , 向客户端读写数据 ,
  • 缓冲区 Buffer : 每个通道 ( Channel ) 都维护了一个数据缓冲区 ( Buffer ) ; 通道 ( Channel ) 可以读写 缓冲区 ( Buffer ) 中的数据 , 是双向的 ; 客户端 也是读写 缓冲区 ( Buffer ) 中的数据 ; 缓冲区 ( Buffer ) 是 通道 ( Channel ) 与 客户端 之间的缓冲区 ;
  • 选择器 Selector : 选择器 ( Selector ) 根据客户端请求 , 选择指定的 通道 ( Channel ) 为客户端进行服务 ;
II . NIO 三大组件交互流程

NIO 服务器端 交互流程 :

① 启动线程 : 服务器端启动一个线程 ;

② 选择器 ( Selector ) 遍历 通道 ( Channel ) : 线程通过 选择器 ( Selector ) 不同的遍历各个 通道 ( Channel ) , 如果发现有 客户端 对应的 通道 ( Channel ) 有网络请求 , 那么开始处理该 通道 ( Channel ) 相关业务逻辑 ;

③ 通道 ( Channel ) 与 缓冲区 ( Buffer ) 交互 : 通道 ( Channel ) 可以 读写 缓冲区 ( Buffer ) 中的数据 ;

④ 缓冲区 ( Buffer ) 与 客户端交互 : 缓冲区 ( Buffer ) 与 客户端 进行数据读写交互 ;

III . NIO 缓冲区

缓冲区 机制 : 缓冲区 ( Buffer ) 向上与 通道 ( Channel ) 进行数据读写交互 , 向下与 客户端 进行数据读写交互 , 客户端 与 通道 ( Channel ) 不直接进行数据通信 ;

① 缓冲区 ( Buffer ) 作用 : 缓冲区 ( Buffer ) 是实现非阻塞机制的重要途径 ;

② 编程风格 : NIO 也称为 面向 缓冲区 编程 ;

③ BIO 阻塞机制 : BIO 中 客户端 与 服务器端 进行交互 , 需要阻塞等待服务器的响应 , 服务器在建立连接后 , 也需要阻塞等待客户端的后续数据 ;

④ NIO 非阻塞机制 : 客户端请求服务器端后 , 将请求数据写入服务器端的 缓冲区 ( Buffer ) 中 , 服务器端通过 选择器 ( Selector ) 轮询 通道 ( Channel ) , 查询 缓冲区 ( Buffer ) 中是否有请求数据 , 客户端不用阻塞等待服务器端响应 , 服务器端也不用阻塞等待客户端的请求 , 因此这里实现了非阻塞机制 ;

非阻塞说明 : 当选择器 ( Selector ) 选择某个 通道 ( Channel ) 时 , 服务器端线程 从通道 ( Channel ) 中读取用户请求的数据 , 读取完毕之后 , 处理该请求处理 , 如果没有读取到用户请求数据 , 就会轮询其它的 通道 ( Channel ) , 如果所有的 通道 ( Channel ) 都没有事件触发 , 线程做其它事情 , 不会在此阻塞等待用户数据 ;

基于事件驱动 : 选择器 ( Selector ) 可以感知到 通道 ( Channel ) 中的事件 , 线程就会处理与该通道 ( Channel ) 相关业务 , 如果 通道 ( Channel ) 没有触发事件 , 那么线程去做其它事 ;

IV . NIO 与 BIO 对比

1 . 数据处理方式对比 :

① BIO 数据处理方式 : BIO 以 流的方式读写数据 , 输入流 读取数据 , 输出流 写出数据 ; 输入流 和 输出流 又分别有 字节流 , 字符流 分类 ;

② NIO 数据处理方式 : NIO 以 缓冲区 ( Buffer ) 数据块的方式处理数据 , 该处理数据的效率 , 远远高于以 流 的方式读写数据的效率 ;

  • 客户端 与 服务器交互时 , 客户端将数据 写入到 缓冲区 ( Buffer ) , 等待服务器端 通道 ( Channel ) 读取该缓冲区的数据 ;
  • 服务器 与 客户端交互时 , 服务器将数据 通过 通道 ( Channel ) 写出到缓冲区中 , 等待 客户端 读取 ;

2 . IO 模型 阻塞类型对比 : BIO 是 同步阻塞 型 IO ; NIO 是 同步非阻塞 型 IO ;

V . NIO 线程分配

BIO 模型 : 在 BIO 模型中 , 如果 一万 客户端 与 服务器端保持连接通信 , 并进行数据交互 , 就需要有 一万个线程 维护这些操作 ;

BIO 模型中 ,

10000

客户端连接 , 对应

10000

线程 ;

NIO 模型 : 在 NIO 模型中 , 如果 一万 客户端 与 服务器端保持连接通信 , 并进行数据交互 , 那么假设分配

100

个线程 , 每个线程都有对应的 选择器 ( Selector ) , 每个 选择器 ( Selector ) 轮询

100

个 通道 ( Channel ) , 每个 通道 ( Channel ) 对应 一个 缓冲区 ( Buffer ) ;

NIO 模型中 ,

10000

客户端连接 , 对应

10000

个缓冲区 ( Buffer ) ,

10000

个 通道 ( Channel ) ,

100

个线程 ;

VI . 缓冲区 ( Buffer ) 示例

Buffer 有

7

个子类 , 分别对应

8

大基础数据 ( Boolean 除外 ) , 这里使用 IntBuffer 作示例说明 ;

缓冲区 ( Buffer ) 代码示例 :

需求 : 创建一个 存放 int 数据的 缓冲区 ( Buffer ) , 其容量为

8

, 将

8

个 int 值存入缓冲区 , 翻转后 , 按照存放顺序打印出来 ;

代码语言:javascript复制
import java.nio.IntBuffer;

public class BufferDemo {
    public static void main(String[] args) {
        //创建一个存储 Int 类型数据的 Buffer , 可以存储 8 个 Int 数据
        IntBuffer buffer = IntBuffer.allocate(8);
        //向 Buffer 中写入数据
        for(int i = 0; i < buffer.capacity(); i   ){
            buffer.put(i);
        }

        //从 Buffer 中取出数据
        //先将 Buffer 翻转一下 , 然后读取 , 读出的数据与存储的数据顺序一样
        buffer.flip();
        //循环读取 buffer 中的 Int 数据, 维护了一个索引 ,
        //代表当前操作的数据索引 , 即 position
        while (buffer.hasRemaining()){
            System.out.println("position "   buffer.position()   " . "   buffer.get());
        }
    }
}

执行结果 :

代码语言:javascript复制
position : 0 . 0
position : 1 . 1
position : 2 . 2
position : 3 . 3
position : 4 . 4
position : 5 . 5
position : 6 . 6
position : 7 . 7

0 人点赞