-
Netty 框架学习 —— 预置的 ChannelHandler 和编解码器
Netty 为许多提供了许多预置的编解码器和处理器,几乎可以开箱即用,减少了在烦琐事务上话费的时间和精力
|
检测空闲连接以及超时对于释放资源来说至关重要,Netty 特地为它提供了几个 ChannelHandler 实现
下述代码展示了当使用通常的发送心跳消息到远程节点的方法时,如果 60 秒内没有接收或者发送任何数据,我们将得到通知,如果没有响应,则连接会关闭
|
基于分隔符的消息协议使用定义的字符来标记消息或者消息段的开头或者结尾,下表列出的解码器能帮助你定义可以提取由任意标记序列分隔的帧的自定义解码器
下述代码展示了如何使用 LineBasedFrameDecoder 处理由行尾符分隔的帧
如果你还使用除了行尾符之外的分隔符来分隔帧,那么你还可以使用 DelimiterBasedFrameDecoder,只需要将特定的分隔符序列指定到其构造函数即可
作为示例,我们将使用下面的协议规范:
- 传入数据流是一系列的帧,每个帧都由换行符 \n 来分隔
- 每个帧都由一系列元素组成,每个元素由单个空格字符分隔
- 一个帧的内容代表一个命令,定义为一个命令名称后跟着数目可变的参数
基于这个协议,我们的自定义解码器将定义以下类:
- Cmd —— 将帧的命令存储在 ByteBuf 中,一个 ByteBuf 用于名称,另一个用于参数
- CmdDecoder —— 从被重写了的 decode() 方法中获取一行字符串,从它的内容构建一个 Cmd 实例
- CmdHandler —— 从 CmdDecoder 获取解码的 Cmd 对象,并对它进行一些处理
|
基于长度的协议通过将它的长度编码到帧的头部来定义帧,而不是使用特殊的分隔符来标记它的结束,下表列出 Netty 提供的用于处理这种类型的协议的两种解码器
你经常会遇到被编码到消息头部的帧大小不是固定值的协议,为了处理这种变长帧,你可以使用 LengthFieldBasedFrameDecoder,它将从头部字段确定帧长,然后从数据流中提取指定的字节数
下图展示了一个示例,其中长度字段在帧中的偏移量为 0,并且长度为 2 字节
下述代码展示了如何使用其 3 个构造函数分别为 maxFrameLength、lengthFieldOffser 和 lengthFieldLength 的构造函数。在这个场景下,帧的长度被编码到了帧起始的前 8 个字节中
|
因为网络饱和的可能性,如何在异步框架中高效地写大块的数据是一个特殊的问题。由于写操作是非阻塞的,所以即时没有写出所有的数据,写操作也会在完成时返回并通知 ChannelFuture。当这种情况发生时,如果仍然不停地写入,就有内存耗尽的风险。所以在写大型数据时,需要考虑处理远程节点的连接是慢速连接的情况,这种情况会导致内存释放的延迟。让我们考虑下将一个文件内容写出到网络的情况
NIO 的零拷贝特性,这种特性消除了将文件的内容从文件系统移动到网络栈的复制过程。所有这一切都发生在 Netty 的核心中,所以应用程序需要做的就是使用一个 FileRegion 接口的实现
下述代码展示了如何通过从 FileInputStream 创建一个 DefaultFileRegion,并将其写入 Channel
这个示例只适用于文件内容的直接传输,不包括应用程序对数据的任何处理。在需要将数据从文件系统复制到用户内存中时,可以使用 ChunkedWriteHandler,它支持异步写大型数据流,而又不会导致大量的内存消耗
interface ChunkedInput<B> 中的类型参数 B 是 readChunk() 方法返回的类型。Netty 预置了该接口的四个实现,如表所示,每个都代表了一个将由 ChunkedWriteHandler 处理的不定长度的数据流
下述代码说明了 ChunkedStream 的用法,它是实践中最常用的实现。所示的类使用了一个 File 以及一个 SSLContext 进行实例化,当 initChannel() 方法被调用时,它将使用所示的 ChannelHandler 链初始化该 Channel
当 Channel 的状态变为活动时,WriteStreamHandler 将会逐块地把来自文件中的数据作为 ChunkedStream 写入
|
JDK 提供了 ObjectOutputStream 和 ObjectInputStream,用于通过网络对 POJO 的基本数据类型和图进行序列化和反序列化。该 API 并不复杂,可以被应用于任何实现了 java.io.Serializable 接口的对象。但它的性能并不高效,在这一节,我们将看到 Netty 如何实现序列化
如果你的程序必须要和使用了 ObjectOutputStream 和 ObjectInputStream 的远程节点交互,并且考虑兼容性,那么 JDK 序列化将是正确的选择,下表列出了 Netty 提供的用于和 JDK 进行交互操作的序列化类
Protocol Buffers 是一种由 Google 公司开发的、开源的数据交换格式,以一种紧凑而高效的方式对结构化的数据进行编码以及解码,能跨多语言使用。下表展示了 Netty 为支持 Protobuf 所提供的 ChannelHandler 实现
出处:https://www.cnblogs.com/Yee-Q/p/14965722.html