Netty 系列笔记之三种 IO 模式

目录

一、引言

二、IO 模式的特征

三、IO 三种模式

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

五、Java NIO 核心组件

六、结语


一、引言

在网络编程中,我们经常听到各种各样的名词:阻塞、非阻塞、异步、同步。这些,都是 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) NIO AIO(Removed)
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 都是支持的,严谨的说是曾经支持过。

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 的核心组件,并学会如何使用它们。 

猜你喜欢

转载自blog.csdn.net/qq_46388795/article/details/109036777