码恋 码恋

ALL YOUR SMILES, ALL MY LIFE.

目录
Netty 系列笔记之三种 IO 模式
/  

Netty 系列笔记之三种 IO 模式

一、引言

在网络编程中,我们经常听到各种各样的名词:阻塞、非阻塞、异步、同步。这些,都是 IO 模式的特征。本篇说明了 IO 三种模式,以及简单提及了 NIO 的三大核心组件。

二、IO 模式的特征

1、阻塞与非阻塞
  • 阻塞:数据没有传过来时,读会一直阻塞直到有数据传过来;当缓冲区被写满时,写操作也被阻塞。
  • 非阻塞:非阻塞遇到上述情况时,直接返回,不会等待。
2、同步与异步
  • 同步:数据就绪后需要自己读。
  • 异步:数据就绪后直接读好再回调给程序。

三、IO 三种模式

名称模式备注
BIO同步阻塞Blocking IO,始于 JDK 1.4 之前
NIO同步非阻塞New IO 或 Non Blocking IO,始于 JDK 1.4
AIO异步Async IO

四、Netty 对三种 IO 模式的支持

BIO -> OIO(Deprecated)NIOAIO(Removed)
Common Linux MacOS/BSD
ThreadPerChannelEventLoopGroupNioEventLoopGroup EpollEventLoopGroup KQueueEventLoopGroupAioEventLoopGroup
ThreadPerChannelEventLoop NioEventLoop EpollEventLoop KQueueEventLoop AioEventLoop
OioServerSocketChannel NioServerSocketChannel EpollServerSocketChannel KQueueServerSocketChannel AioServerSocketChannel
OioSocketChannelNioSocketChannelEpollSocketChannel KQueueSocketChannelAioSocketChannel

由上面的表格可以看到 Netty 对于三种 IO 都是支持的,严谨的说是曾经支持过。

1、为什么 Netty 仅支持 NIO 了?
  • BIO 在 Netty 中称 OIO,即 old IO 。我们知道在连接数多的情况下,阻塞意味着性能低,耗资源,所以 OIO 在 Netty 中已经不推荐使用了。

  • AIO 其实在 Netty 5 版本中已经做好支持了,后来在官网发布后一段时间又删除了。究其原因如下:

    • Windows 系统的 AIO 实现已经非常成熟了,但是很少用来做服务器。
    • Linux 常用来做服务器,但是 AIO 实现不够成熟。
    • Linux 系统下 AIO 相比较 NIO 性能提示不明显。
    • 更多的维护成本。
2、为什么 Netty 有多种 NIO 实现?

NIO 有一个 Common 实现,针对不同的平台又有其相应的实现。通用的 NIO 实现在 Linux 下也是使用 epoll ,那么既然有了 Common 实现,为什么还要做不同的平台实现呢?

  • JDK 在不同的平台有不同的版本,Netty 如此设计也是基于同样的考虑,相比之下 Netty 暴露了更多的可控参数,例如 JDK 的 NIO 实现默认是水平触发,Netty 默认边缘触发并和水平触发可切换。
  • Netty 实现垃圾回收更少,性能更好

❤ tips:关于 epoll 的水平触发和边缘触发。

在 Linux 的网络编程中,内核使用 epoll 机制做事件触发,其中 epoll_wait 函数是 epoll 接口的三个函数之一,用于轮询I/O事件的发生。

水平触发通俗来讲:只要有数据,epoll_wait 函数就一直返回;边缘触发通俗来讲:只有 socket 状态发生变化,epoll_wait 函数才会返回。

关于 epoll 的更多,小伙伴若感兴趣可自行谷歌了解。

3、NIO 一定优于 BIO 吗?

相比较 NIO 而言,BIO 的代码实现简单,在特定连接数并发数少的场景下,BIO 的性能不输于 NIO 。

基于以上,学习 Netty 我们必须对 Java 的 NIO 有一定的基础,所以后面一些篇幅是对 Java 的 NIO 知识做一个回顾,即下面讲的 NIO 基于 Java 本身,与 Netty 无关,请小伙伴注意。

五、Java NIO 核心组件

NIO 由三大核心组件组成:

  • Channel
  • Buffer
  • Selector

传统 IO 基于流(Stream)操作,面向字节流或字符流。NIO 与之最大的不同就是基于 Channel 和 Buffer 操作,面向缓冲区。NIO 通过缓冲区可以读取任意位置的数据,相比传统 IO 灵活性大大增强,同时也不会阻塞当前线程。

1、Channel

不同于传统 IO 的流,读写需要使用不同的输入输出流,Channel 是双向的。这意味着它既可以用来进行读操作,又可以用来进行写操作。

NIO中的Channel的主要实现有:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel
2、Buffer

Buffer 是缓冲区,本质上是一块内存区域。NIO 中的关键 Buffer 实现有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分别对应基本数据类型: byte, char, double, float, int, long, short。以及 MappedByteBuffer, HeapByteBuffer, DirectByteBuffer 等等。

3、Selector

一个 Selector 可以注册多个 Channel ,Selector 不断地执行查询并判断这些 Channel 是否存在已就绪的 IO 操作,如可读,可写,网络连接已完成等。通过这样的机制,单线程下一个 Selector 就可以管理多个 Channel 了。

六、结语

本篇介绍了三种 IO 模式,以及 Netty 关于三种模式的一些问题讨论,并在结尾简单列举了 NIO 的核心组件,接下来我们将详细的了解 NIO 的核心组件,并学会如何使用它们。



❤ 转载请注明本文地址或来源,谢谢合作 ❤


center