Netty框架学习之(三):细说Netty的数据传输

1. 概述

使用Java 自带的API开发IO系统时,如果需要对传输的方式进行切换,例如从阻塞传输切换到非阻塞传输, 那么可能会由于两种方式的API不兼容问题需要大面积的修改代码。然而 Netty 则为它所有的传输方式提供了一个通用 API,这使得只需要修改一下对象申明的类型就能完成传输方式的切换,例如从OIO切换到NIO只需要如下操作:

OIO的代码:
EventLoopGroup group = new OioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(OioServerSocketChannel.class)
            .........
        } finally {
            group.shutdownGracefully().sync();
        }

NIO的代码:
EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(group)
                    .channel(NioServerSocketChannel.class)
            .........
        } finally {
            group.shutdownGracefully().sync();
        }

是不是很方便?

2. API说明

传输API的核心Channel,它被用于所有的IO操作,Channel的类图如下所示:

这里写图片描述

如图所示,每个 Channel 都将会被分配一个 ChannelPipeline 和 ChannelConfig。
ChannelConfig 包含了该 Channel 的所有配置设置,并且支持热更新.

由于 Channel 是独一无二的,所以为了保证顺序将 Channel 声明为 java.lang.
Comparable 的一个子接口。因此,如果两个不同的 Channel 实例都返回了相同的散列码,那么 AbstractChannel 中的 compareTo()方法的实现将会抛出一个 Error.

ChannelPipeline 持有所有将应用于入站和出站数据以及事件的 ChannelHandler 实
例,这些 ChannelHandler 实现了应用程序用于处理状态变化以及数据处理的逻辑,例如:

  • 将数据从一种格式转换为另一种格式;
  • 提供异常的通知;
  • 提供 Channel 变为活动的或者非活动的通知;
  • 提供当 Channel 注册到 EventLoop 或者从 EventLoop 注销时的通知;
  • 提供有关用户自定义事件的通知。

也可以根据需要通过添加或者移除ChannelHandler实例来修改ChannelPipeline,通过利用Netty的这项能力可以构建出高度灵活的应用程序。

3. 内置的传输方式

Netty内置了多种类型的传输方式,不同的传输方式有不同的应用场景与支持的协议,目前常见的类型包括以下几种

3.1 NIO

NIO类型的传输提供了一个所有 I/O 操作的全异步的实现,主要利用了自JAVA 自带 NIO 子系统的选择器API。

3.2 Epoll

Netty 的 NIO 传输基于 Java 提供的异步/非阻塞网络编程的通用抽象。
虽然这保证了 Netty 的非阻塞 API 可以在任何平台上使用,但它也包含了相应的限制,因为 JDK
为了在所有系统上提供相同的功能,必须做出妥协。

Epoll自Linux内核版本 2.5.44(2002)被引入,提供了比旧的POSIX select和poll系统调用更好的性能。如果你的应用程序旨在运行于Linux系统,那么可以考虑利用这个版本的传输;你将发现在高负载下它的性能要优于JDK的NIO实现

3.3 OIO

Netty 的 OIO 传输实现代表了一种折中:它可以通过常规的传输 API 使用,但是由于它
是建立在 java.net 包的阻塞实现之上的,所以它不是异步的。但是,它仍然非常适合于某些用途。例如,你可能需要移植使用了一些进行阻塞调用的库(如JDBC)的遗留代码,而将逻辑转换为非阻塞的可能也是不切实际的。相反,你可以在短期内使用Netty的OIO传输,然后再将你的代码移植到纯粹的异步传输上。

Netty是如何能够使用和用于异步传输相同的API来支持OIO的呢?
答案就是, Netty利用了SO_TIMEOUT这个Socket标志,它指定了等待一个I/O操作完成的最大毫秒数。如果操作在指定的时间间隔内没有完成, 则将会抛出一个SocketTimeout Exception。 Netty将捕获这个异常并继续处理循环。在EventLoop下一次运行时,它将再次尝试。这实际上也是类似于Netty这样的异步框架能够支持OIO的唯一方式。

3.4 Local

Netty 提供了一个 Local 传输,用于在同一个 JVM 中运行的客户端和服务器程序之间的异步通信。

在同一个 JVM 内部的通信,不需要通过网络暴露服务,是
Local 传输的完美用例。这将消除所有真实网络操作的开销,同时仍然使用你的 Netty 代码库。如果随后需要通过网络暴露服务,那么你将只需要把传输改为 NIO 或者 OIO 即可。

3.5 Embedded

如果你想要为自己的 ChannelHandler 实现编
写单元测试,可以考虑使用 Embedded 传输。这既便于测试你的代码,而又不需要创建大
量的模拟(mock)对象。你的类将仍然符合常规的 API 事件流, 保证该 ChannelHandler
在和真实的传输一起使用时能够正确地工作。

猜你喜欢

转载自blog.csdn.net/sun7545526/article/details/80436184