在网络编程中,我们经常听到各种各样的名词:阻塞、非阻塞、异步、同步。这些,都是 IO 模式的特征。本篇说明了 IO 三种模式,以及简单提及了 NIO 的三大核心组件。
名称 | 模式 | 备注 |
---|---|---|
BIO | 同步阻塞 | Blocking IO,始于 JDK 1.4 之前 |
NIO | 同步非阻塞 | New IO 或 Non Blocking IO,始于 JDK 1.4 |
AIO | 异步 | Async IO |
NIO | ||||
---|---|---|---|---|
Common | Linux | MacOS/BSD | ||
ThreadPerChannelEventLoopGroup | NioEventLoopGroup | EpollEventLoopGroup | KQueueEventLoopGroup | AioEventLoopGroup |
ThreadPerChannelEventLoop | NioEventLoop | EpollEventLoop | KQueueEventLoop | AioEventLoop |
OioServerSocketChannel | NioServerSocketChannel | EpollServerSocketChannel | KQueueServerSocketChannel | AioServerSocketChannel |
OioSocketChannel | NioSocketChannel | EpollSocketChannel | KQueueSocketChannel | AioSocketChannel |
由上面的表格可以看到 Netty 对于三种 IO 都是支持的,严谨的说是曾经支持过。
BIO 在 Netty 中称 OIO,即 old IO 。我们知道在连接数多的情况下,阻塞意味着性能低,耗资源,所以 OIO 在 Netty 中已经不推荐使用了。
AIO 其实在 Netty 5 版本中已经做好支持了,后来在官网发布后一段时间又删除了。究其原因如下:
NIO 有一个 Common 实现,针对不同的平台又有其相应的实现。通用的 NIO 实现在 Linux 下也是使用 epoll ,那么既然有了 Common 实现,为什么还要做不同的平台实现呢?
❤ tips:关于 epoll 的水平触发和边缘触发。
在 Linux 的网络编程中,内核使用 epoll 机制做事件触发,其中 epoll_wait 函数是 epoll 接口的三个函数之一,用于轮询I/O事件的发生。
水平触发通俗来讲:只要有数据,epoll_wait 函数就一直返回;边缘触发通俗来讲:只有 socket 状态发生变化,epoll_wait 函数才会返回。
关于 epoll 的更多,小伙伴若感兴趣可自行谷歌了解。
相比较 NIO 而言,BIO 的代码实现简单,在特定连接数并发数少的场景下,BIO 的性能不输于 NIO 。
基于以上,学习 Netty 我们必须对 Java 的 NIO 有一定的基础,所以后面一些篇幅是对 Java 的 NIO 知识做一个回顾,即下面讲的 NIO 基于 Java 本身,与 Netty 无关,请小伙伴注意。
NIO 由三大核心组件组成:
传统 IO 基于流(Stream)操作,面向字节流或字符流。NIO 与之最大的不同就是基于 Channel 和 Buffer 操作,面向缓冲区。NIO 通过缓冲区可以读取任意位置的数据,相比传统 IO 灵活性大大增强,同时也不会阻塞当前线程。
不同于传统 IO 的流,读写需要使用不同的输入输出流,Channel 是双向的。这意味着它既可以用来进行读操作,又可以用来进行写操作。
NIO中的Channel的主要实现有:
Buffer 是缓冲区,本质上是一块内存区域。NIO 中的关键 Buffer 实现有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分别对应基本数据类型: byte, char, double, float, int, long, short。以及 MappedByteBuffer, HeapByteBuffer, DirectByteBuffer 等等。
一个 Selector 可以注册多个 Channel ,Selector 不断地执行查询并判断这些 Channel 是否存在已就绪的 IO 操作,如可读,可写,网络连接已完成等。通过这样的机制,单线程下一个 Selector 就可以管理多个 Channel 了。
本篇介绍了三种 IO 模式,以及 Netty 关于三种模式的一些问题讨论,并在结尾简单列举了 NIO 的核心组件,接下来我们将详细的了解 NIO 的核心组件,并学会如何使用它们。