Java进阶面霸|NIO开发需要知道的Netty精粹,JAVA( 二 )


Java进阶面霸|NIO开发需要知道的Netty精粹,JAVA
文章图片
JAVANIO核心组件
在JAVANIO中 , 基本上所有的IO都是从Channel开始的 , 读取操作即从Channel读到Buffer , 写操作即从Buffer写入Channel 。
Java进阶面霸|NIO开发需要知道的Netty精粹,JAVA
文章图片
NIO读写示意图Channel
在网络IO方面 , Channel的主要实现是ServerSocketChannel和SocketChannel 。 他们都代表一个面向流的可监听读写事件的socket 。 ServerSocketChannel是用于服务器端的socket , 他提供了一个静态工具方法open来为用户提供获取Channel的工具:publicstaticServerSocketChannelopen()throwsIOException{returnSelectorProvider.provider().openServerSocketChannel();}
其中涉及到的SelectorProvider用于创建具体的Channel , SelectorProvider的获取有三种途径 , 首先从系统属性中获取key为java.nio.channels.spi.SelectorProvider的值 , 如果没有则基于SPI机制来获取 , 如果再没有则最后提供默认的 , 这个默认值跟操作系统平台相关 , 比如我的mac系统 , JDK提供的默认Provider是KQueueSelectorProvider 。
Java进阶面霸|NIO开发需要知道的Netty精粹,JAVA
文章图片
ServerSocketChannel提供的接口
ServerSocketChannel的使用方式是面向服务器端的 , 一般的开发流程是:
获取一个ServerSocketChannel 。
设置网络操作 , 这些参数主要是和TCP协议有关 。
将ServerSocketChannel注册到Selector(多路复用器) 。
将ServerSocketChannel和某个具体的地址绑定 。
用户像多路复用器设置感兴趣的IO事件 。
用户线程以阻塞或非阻塞方式轮询Selector来查看是否有就绪的IO事件 。
用户针对不同的IO事件对Channel进行具体的IO操作 。
SocketChannel主要是面向客户端的开发的 , 也是以open方式获取channel , 客户端的开发流程大致如下:
获取一个SocketChannel 。
设置Channel为非阻塞方式 。
获取Selector 。
将channel注册到Selector , 并监听CONNECT事件 。
调用channel的connect方法连接指定的服务器和端口 。
如果连接成功则进行IO操作 , 如果没成功则轮询Selector处理CONNECT事件 。 Selector
Selector是JAVANIO中的多路复用器 , 配合SelectionKey使用 , SelectionKey代表着一个Channel和Selector的关系的抽象 , Channel向Selector注册的时候产生 , 由Selector维护 。 Selector维护着三个SelectionKey的集合:
keyset:这个集合包含所有向Selector注册的Channel产生的SelectionKey , 这个集合中的SelectionKey是不能直接被修改的 , 除非SelectionKey被channel , 并且发生select的时候SelectionKey才被移出 。
selectedkeyset:这个集合是keyset集合的子集 , 当有SelectionKey关联的Channel有Channel向Selector注册的IO事件就绪的时候并且有select操作 , 对应的SelectionKey会被放到selectedkeyset中 。 因为这个集合中的SelectionKey可以通过直接调用Set的remove将SelectionKey移除 。
cancelled-key:这个集合是也是keyset的子集 。 当有已经向Selector注册的Channel发生degistered的时候 , SelectionKey将被放到这个集合 , 并且在下一次select的时候被从所有的集合中移出 。
三种集合的流转我画个图表示一下:
Java进阶面霸|NIO开发需要知道的Netty精粹,JAVA
文章图片
Selector的SelectionKey集合流转图
在开发过程中 , 我们可以将多个Channel注册到一个Selector实例中 , 用一个线程来处理所有的IO事件 , 我们也可以将多个Channel注册到多个Selector实例中 , 结合高效的线程模型可以达到很好的效果 。 ByteBuffer


推荐阅读