Java NIO 的 Selector:

    • java 的 NIO,用非阻塞的 IO 方式,可以用一个线程,处理多个的客户端连接,就会使用到 Selector(选择器)
    • Selector 能够检测多个注册通道上是否有事件发生(多个 Channel 以事件的方式可以注册到同一个 Selector ),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求
    • 只有在连接/通道真正读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程
    • 避免了多线程之间的上下文切换导致的开销

    java.nio.channels.Selector 接口的常用方法:

    • static Selector open() throws IOException:得到一个选择器对象
    • Set selectedKeys():从内部集合中得到所有的 SelectionKey
    • int select(long timeout) throws IOException:监控所有注册的通道,当其中有IO操作可以进行时,将对应的selectionKey加入到内部集合中并返回,参数用来设置超时时间

    NIO 非阻塞网络编程相关的Selector、SelectionKey、ServerSocketChannel、SocketChannel 关系:

    1. 当客户端连接时,会通过 ServerSocketChannel 获得一个 SocketChannel
    2. 将 SocketChannel 注册到 Selector 上,即 register(Selector sel , int ops),一个 Selector 上可以注册多个 SocketChannel
    3. 注册后返回一个和该 Selector 关联的 SelectionKey
    4. 使用 Selector 的 select() 方法进行监听,返回有事件发生的通道的个数
    5. 然后得到 SelectionKey(有事件),然后 SelectionKey.channel() 得到 SocketChannel,通过得到的 channel,完成事件处理

    image.png

    Selector 的创建:Selector selector = Selector.open();
    向 Selector 注册通道:SelectableChannel.register()
    在与 Selector 一起使用时,Channel 必须处于非阻塞模式下,这意味着 Selector 不能和 FileChannel 连用,因为 FileChannel 不能切换到非阻塞模式,而套接字通道可以。

    SelectionKey:

    • Selector selector():得到与之关联的 Selector 对象
    • SelectableChannel channel():得到与之关联的通道
    • Object attachment():得到与之关联的共享数据(缓冲区)
    • SelctionKey interestOps(int ops):设置或改变监听事件
    • boolean isAcceptable():是否可以accept
    • boolean isReadable():是否可以读
    • boolean isWritable():是否可以写

    四个事件常量:

    1. SelectionKey.OP_CONNECT
    2. SelectionKey.OP_ACCEPT
    3. SelectionKey.OP_READ
    4. SelectionKey.OP_WRITE

    通道触发了一个事件的意思是该事件已经就绪,所以某个channel成功连接到另一个服务器称为“连接就绪”。一个server socket channel准备好接收新进入的连接称为“接收就绪”。一个有数据可读的通道可以说是“读就绪”。等待写数据的通道可以说是“写就绪”。当对不止一种事件感兴趣时,使用位或运算符连接,即“|”

    ServerSocketChannel :在服务器端监听新的客户端 socket 连接

    • static ServerSocketChannel open():得到一个 ServerSocketChannel 通道
    • ServerSocketChannel bind(SocketAddress local):设置服务器端口
    • SelectableChannel configureBlocking(boolean block):设置阻塞或非阻塞模式。true,阻塞模式;false,非阻塞模式
    • SocketChannel accept():接受一个客户端连接,返回代表这个连接的通道对象
    • SelectionKey register(Selector sel , int ops):注册一个选择器并设置监听事件

    image.png