参考 《Netty 权威指南》

在介绍 NIO 编程之前,我们首先需要澄清一个概念:NIO 到底是什么的简称?

NIO 官方的的叫法是 New I/O,但是,由于之前老的 I/O 类库是阻塞 I/O,New I/O 类库的目的就是要让 Java 支持非阻塞 I/O,所以,更多的人喜欢称之为非阻塞 I/O(Non-block I/O)。

与 Socket 类和 ServerSocket 类相对应,NIO 也提供了 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。

NIO 类库简介

下面我们对 NIO 的一些概念和功能做下简单介绍,以便大家能够快速地了解 NIO 类库和相关概念。

缓冲区 Buffer

我们首先介绍缓冲区(Buffer)的概念,Buffer 是一个对象,它包含一些要写入或者要读出的数据。在 NIO 类库中加入 Buffer 对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,可以将数据直接写入或者将数据直接读到 Stream 对象中。

在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的;在写入数据时,写入到缓冲区中。任何时候访问 NIO 中的数据,都是通过缓冲区进行操作。

缓冲区实质上是一个数组。通常它是一个字节数组(ByteBuffer),也可以使用其他种类的数组。但是一个缓冲区不仅仅是一个数组,缓冲区提供了对数据的结构化访问以及维护读写位置(limit)等信息。

最常用的缓冲区是 ByteBuffer,一个 ByteBuffer 提供了一组功能用于操作 byte 数组。除了 ByteBuffer,还有其他的一些缓冲区,事实上,每一种 Java 基本类型(除了 Boolean 类型)都对应有一种缓冲区,具体如下:

  • ByteBuffer:字节缓冲区
  • CharBuffer:字符缓冲区
  • ShortBuffer:短整型缓冲区
  • IntBuffer:整型缓冲区
  • LongBuffer:长整型缓冲区
  • FloatBuffer:浮点型缓冲区
  • DoubleBuffer:双精度浮点型缓冲区

缓冲区的继承关系如下图所示:

image.png

每一个 Buffer 类都是 Buffer 接口的一个子实例。除了 ByteBuffer,每一个 Buffer 类都有完全一样的操作,只是它们所处理的数据类型不一样。因为大多数标准 I/O 操作都使用 ByteBuffer,所以它除了具有一般缓冲区的操作之外还提供一些特有的操作,方便网络读写。

通道 Channel

Channel 是一个通道,它就像自来水管一样,网络数据通过 Channel 读取和写入。通道与流的不同之处在于通道是双向的,流只是在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类),而通道可以用于读、写或者二者同时进行。

因为 Channel 是全双工的,所以它可以比流更好地映射底层操作系统的 API。特别是在 UNIX 网络编程模型中,底层操作系统的通道都是全双工的,同时支持读写操作。

Channel 的类图继承关系如下图所示。

image.png

自顶向下看,前面主要是 Channel 接口,用于定义它的功能,后面是一些具体的功能类(抽象类)。从类图可以看出,实际上 Channel 可以分为两大类:用于网络读写 SelectableChannel 和用于文件操作的 FileChannel。

ServerSocketChannel 和 SocketChannel 都是 SelectableChannel 的子类。

多路复用器 Selector

在本节中,我们将探索多路复用器 Selector,它是 Java NIO 编程的基础,熟练地掌握 Selector 对于 NIO 编程至关重要。多路复用器提供选择已经就绪的任务的能力。简单来讲,Selector 会不断的轮询注册在其上的 Channel,如果某个 Channel 上面有新的 TCP 连接接入、读和写事件,这个 Channel 就处于就绪状态,会被 Selector 轮询出来,然后通过 SelectionKey 可以获取就绪 Channel 的集合,进行后续的 IO 操作。

一个多路复用器 Selector 可以同时轮询多个 Channel,由于 JDK 使用了 epoll() 代替传统的 select 实现,所以它并没有最大连接句柄 1024/2048 的限制。这也就意味着只需要一个线程负责 Selector 的轮询,就可以接入成千上万的客户端。

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/unlipv 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。