前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Netty】NIO 选择器 ( Selector ) 简介

【Netty】NIO 选择器 ( Selector ) 简介

作者头像
韩曙亮
发布2023-03-27 20:41:08
4080
发布2023-03-27 20:41:08
举报

文章目录

I . 选择器 ( Selector )

在这里插入图片描述
在这里插入图片描述

NIO ( 非阻塞 IO ) 使用单个线程管理多个 通道 ( Channel ) 就是通过 选择器 ( Selector ) 实现的 ;

选择器 ( Selector ) 简介 :

① 注册机制 : 选择器 ( Selector ) 可以注册多个 通道 ( Channel ) , 注册过程是以事件的方式进行注册 , 如果有事件触发 , 那么 选择器 ( Selector ) 就会针对该事件类型进行对应处理 ;

② 注册后的操作 : 通道 注册给 选择器 之后 , 每个线程对应的 选择器 ( Selector ) 才能监控客户端向服务器中对应的 通道 ( Channel ) 写出的数据 ;

③ 轮询机制 : 选择器 ( Selector ) 工作时 , 不停地在轮询其所注册的 通道 ( Channel ) , 处理该 通道 所注册的对应事件 ;

④ 非阻塞机制 : 只有 客户端连接 有数据写入时 , 才会触发事件 , 线程才开始处理该客户端对应的操作 , 如果没有数据写入 , 线程也不会在此阻塞 , 转而处理其它事务 ;

II . 选择器 ( Selector ) 与 NIO 特性

选择器 ( Selector ) 与 NIO 特性 :

① 多路复用 : 选择器 ( Selector ) 又称为 多路复用器 , 为服务器的一个线程管理多个客户端连接 ;

② 轮询机制 : 客户端通过 Socket 向服务器发送数据 , 被 选择器 ( Selector ) 轮询到 , 线程就会开始为该客户端服务 ;

③ 单线程多个连接 : 如果 该客户端 没有发送数据 , 线程不会在此阻塞 , 线程会为其它的客户端服务 , 因此一个线程可以管理与多个客户端的连接 ;

④ 非阻塞 : 服务器端 的线程 不会因为客户端没有发送数据而阻塞 , 因此称为 非阻塞 IO , 该机制提升了线程的 IO 效率 ;

⑤ 优点 : 服务器端单个线程可以非阻塞地并发处理与多个客户端连接的读写操作 , 提高了系统的 可伸缩性 , 性能 ;

III . 选择器 ( Selector ) API 简介

选择器 ( Selector ) 是 NIO 中的三大核心组件之一 ;

下面是 Selector API 相关简介 ;

1 . Selector 抽象类 说明 : Selector 是一个抽象类 , 其中定义了 打开 , 关闭 , 选择 , 键集 ( SelectionKey ) 相关的方法 ;

代码语言:javascript
复制
public abstract class Selector

2 . 打开 关闭 选择器 ( Selector ) 相关方法 :

① Selector open() 方法 : 打开选择器 , 作用是获取一个选择器 ;

② boolean isOpen() 方法 : 判定选择器是否已经打开 ;

③ void close() 方法 : 关闭选择器 ;

3 . 选择 相关方法 : 监听通道事件 , 如果有事件发生 , 返回发生的事件个数 ;

① int select(long timeout) 方法 : 开始监控该 选择器 ( Selector ) 所注册的 通道 ( Channel ) , 如果某个 通道中有 IO 操作触发 , 将 通道 ( Channel ) 对应的 选择键 ( SelectionKey ) 加入到其待处理集合中 ;

  • long timeout 参数 : 设置的超时时间 ;

② int select() 方法 : 监听通道事件 , 如果有事件发生 , 返回发生的事件个数 , 如果没有事件发生会一直保持阻塞 ;

③ int selectNow() 方法 : 监听通道事件 , 如果有事件发生 , 返回发生的事件个数 , 如果没有事件发生 , 返回 0 ;

4 . 选择操作的阻塞说明 :

① 阻塞 : 选择器 ( Selector ) 的 select() 方法执行的是 阻塞 操作 , 直到其所关联的 通道 ( Channel ) 有一个有事件发生 ;

② 带超时的阻塞 : 选择器 ( Selector ) 的 select(long timeout) 方法 是阻塞 操作 , 但是如果 timeout 毫秒内没有事件发生 , 就解除阻塞 ;

③ 非阻塞 : 选择器 ( Selector ) 的 selectNow() 方法是 非阻塞的操作 , 如果当前没有事件发生 , 立刻返回 , 有事件发生将 SelectionKey 放入集合再返回 , 总之不阻塞 ;

5 . 阻塞 唤醒相关方法 :

Selector wakeup() 方法 : 如果 选择器 ( Selector ) 调用了 select() 方法 或 select(long timeout) 方法 , 当前处于阻塞状态 , 那么就会立刻解除阻塞 ;

6 . 键集 相关方法 :

① Set<SelectionKey> selectedKeys() 方法 : 获取 选择器 ( Selector ) 所有有事件发生的通道的 SelectionKey 集合 , 上面的 select() 方法只能选择一个 ;

② Set<SelectionKey> keys() 方法 : 获取 选择器 ( Selector ) 所注册的有的通道的 SelectionKey ;

IV . SelectionKey 简介

SelectionKey 简介 :

① SelectionKey 作用 : SelectorImpl 是 Selector 的实现类 , 在其中可以看到很多 SelectionKey 的 Set 集合 ;

② SelectionKey 集合 : 存储有事件发生的 通道 ( Channel ) 对应的 SelectionKey ;

代码语言:javascript
复制
public abstract class SelectorImpl extends AbstractSelector {
    protected Set<SelectionKey> selectedKeys = new HashSet();
    protected HashSet<SelectionKey> keys = new HashSet();
    private Set<SelectionKey> publicKeys;
    private Set<SelectionKey> publicSelectedKeys;
	
	...
}

③ 通道 注册给 选择器 : 通道 ( Channel ) 注册到 选择器 ( Selector ) 中 , 每个 通道 ( Channel ) 都有一个对应的 SelectionKey ;

④ 事件触发机制 : 选择器 ( Selector ) 监控到某通道有事件发生 , 就会拿到该通道对应发生的事件的 个数 , 之后处理事件时 , 再去遍历 SelectionKey 集合 , 通过 SelectionKey 可以获取对应的 通道 ( Channel ) , 线程开始为该 通道 ( Channel ) 进行服务 ;

⑤ 通过 SelectionKey 获取 通道 ( Channel ) : 在 SelectionKey 中定义了获取 通道 的方法 , 可以直接获取对应的通道 ;

代码语言:javascript
复制
public abstract SelectableChannel channel()

⑥ 获取触发事件的通道 : 调用 选择器 ( Selector ) 的 select() 方法 , 就可以获得有几个 通道 ( Channel ) 中有事件发生 , 将有事件发生的 通道 的 SelectionKey 放入到集合中 ;

⑦ 触发的事件 : 上述集合中每个 SelectionKey 都代表一个对应 通道 ( Channel ) 的事件 , 如 : 客户端 TCP 连接 , 读取数据 , 写出数据 等事件 ;

V . 选择器 ( Selector ) 工作流程

1 . 创建通道 : 服务器端 , 每当有客户端连接服务器时 , 服务器的 ServerSocketChannel 就会创建一个与客户端对应的 SocketChannel ;

2 . 注册通道 : 将创建的 SocketChannel 注册给 选择器 ( Selector ) , 调用通道的 register() 方法将 通道 ( Channel ) 注册给选择器 ( Selector ) ;

① 注册对应关系 : 一个 选择器 ( Selector ) 可以注册多个 通道 ( Channel ) ;

② 注册返回值 : 通道 注册给 选择器 后 , 会返回 SelectionKey , 此时将 SelectionKey 放入 选择器 ( Selector ) 的集合中进行管理 , 调用 选择器的 keys() 方法 , 可以获取这些注册的 SelectionKey 的 Set 集合 ;

③ 常用的注册方法 : ops 指的是关注的事件 ;

代码语言:javascript
复制
SelectionKey register(Selector sel, int ops)
SelectionKey register(Selector sel, int ops, Object att)

3 . 选择器 ( Selector ) 开始监听 : 调用 select() , select(long timeout) , selectNow() 方法 , 以 阻塞或非阻塞 的方式获取其管理的通道中 , 有几个通道触发了事件 ;

事件的种类 :

  • OP_READ : 读取数据事件 ;
  • OP_WRITE : 写出数据事件 ;
  • OP_CONNECT : 连接操作事件 ;
  • OP_ACCEPT : 等待连接操作事件 ;

4 . 获取 SelectionKey : 获取有事件发生的 通道 ( Channel ) 的 SelectionKey ;

5 . 获取 SelectionKey 对应的通道 : 调用 SelectionKey 的 channel() 方法 , 可以获取 SelectionKey 对应的 通道 ( Channel ) ;

6 . 通道 ( Channel ) 处理 : 执行真正的业务处理流程 ;

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
    • I . 选择器 ( Selector )
      • II . 选择器 ( Selector ) 与 NIO 特性
        • III . 选择器 ( Selector ) API 简介
          • IV . SelectionKey 简介
            • V . 选择器 ( Selector ) 工作流程
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档