Java网络编程(1)-NIO三大组件介绍

258 阅读2分钟

概述

NIO(Non-blocking I/O)是Java提供的一种非阻塞IO操作方式,主要用于提高应用程序的并发性能。常用于开发高性能的服务器程序,允许单个线程管理多个网络连接,通过选择器(Selector)来监控多个通道(Channel)的状态。 image.png

  1. channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel。
  2. buffer 则用来缓冲读写数据
  3. 选择器Selector则是用来管理多个连接,当连接中发生事件时,做出响应。

基本运行逻辑

Selector可以检测四种类型的IO事件,这些事件分别对应于SelectionKey的四种状态:

  1. 可读(OP_READ) : 当通道(Channel)处于可读状态时,表示有数据可从通道读取。对于SocketChannel,这意味着新的数据可以被读取。
  2. 可写(OP_WRITE) : 当通道处于可写状态时,表示数据可以被写入通道。对于SocketChannel,这意味着可以向连接的服务器发送数据。
  3. 连接就绪(OP_CONNECT) : 当一个非阻塞的SocketChannel连接到服务器时,如果连接尚未建立,该事件表示连接操作已经完成,并且连接已经建立。这通常用于客户端初始化连接时。
  4. 接受连接(OP_ACCEPT) : 当一个ServerSocketChannel处于可接受状态时,表示新的连接已经到达,服务器可以调用accept()方法来接受新的连接。这通常用于服务器端准备接受新的客户端连接。 image.png 基本运行逻辑:
  5. 创建一个SocketServerChannel,用来接收客户端的连接
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.bind(new InetSocketAddress(8080));
ssc.configureBlocking(false); // 将channel设置成非阻塞模式
  1. 创建Selector,将创建好的channel交给Selector管理,Selector会为每一个注册的channel生成一个key,往后通过该key来获取channel。
//创建Selector
Selector selector = Selector.open();
//将channel交给selector管理
ssc.register(selector, SelectionKey.OP_ACCEPT);
  1. 客户端事件发生,Selector会将发生事件对应的key放入SelectedKeys集合。(注意,Selector只会向集合中添加key,不会删除key,所以要手动删除,所以要用迭代器遍历)
while (true) {
    int count = selector.select();
    // 获取所有事件
    Set < SelectionKey > keys = selector.selectedKeys();
    // 遍历所有事件,逐一处理
    Iterator < SelectionKey > iter = keys.iterator();
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        // 判断事件类型
        if (key.isAcceptable()) {
            ServerSocketChannel c = (ServerSocketChannel) key.channel();
            // 必须处理
            SocketChannel sc = c.accept();
            log.debug("{}", sc);
        }
        // 处理完毕,必须将事件移除
        iter.remove();
    }
}

注意:

  1. selector.select();只会在有事件发生的时候继续运行,否则会阻塞。
  2. 事件发生后,要么处理,要么取消(cancel),不能什么都不做,否则下次该事件仍会触发,这是因为 nio 底层使用的是水平触发