Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder

本文深入分析了Netty中的LengthFieldBasedFrameDecoder,这是一个基于长度字段的解码器,用于处理包含长度字段的数据帧。文章详细介绍了其四个关键属性:lengthFieldOffset、lengthFieldLength、initialBytesToStrip和lengthAdjustment,通过多个示例解释了它们的作用和应用场景。同时,文章探讨了decode()方法的源码,并指出长度字段长度只能为1、2、3、4、8的原因。文章最后总结了LengthFieldBasedFrameDecoder的实现原理,并推荐了其他相关的Netty源码分析文章。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,阅读更多Spring源码分析Java并发编程文章。

微信公众号

前言

在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:LengthFieldBasedFrameDecoder,这是一个基于长度字段的解码器。什么意思呢?就是在发送的数据中,使用一个字段来表示数据的长度,这样当接收方接收到数据后,先读出这个长度字段,读到了长度字段,那就知道了这次发送的数据有多长,这样就能解码出数据了。

属性介绍

LengthFieldBasedFrameDecoder 中有几个重要的属性,其中大分部属性与上一篇文章中提到的解码器中的属性相同,只有 4 个属性是长度字段解码器特有的。如下所示。

// 长度字段的偏移量
private final int lengthFieldOffset;
// 长度字段的长度
private final int lengthFieldLength;
// 长度调整值
private final int lengthAdjustment;
// 跳过的初始字节数
private final int initialBytesToStrip;

// 长度字段结束的偏移量,是通过属性计算出来:lengthFieldOffset + lengthFieldLength
private final int lengthFieldEndOffset;

// ======= 下面属性与其他解码器中类似 =========
// 是否立即抛出失败信息,true表示立即
private final boolean failFast;
// 是否处于丢弃模式,true表示处于丢弃模式
private boolean discardingTooLongFrame;
// 需要丢弃的长度
private long tooLongFrameLength;
// 累计丢弃的字节数
private long bytesToDiscard;

既然说 LengthFieldBasedFrameDecoder 是基于长度字段的解码器,那么就肯定需要有字段告诉我长度在哪儿,也就是处于这一串数据的哪个位置?这个字段就是 lengthFieldOffset,它用来标识长度字段处于这一串数据中的哪一个地方。

另外,数据有长度,是用一个数字来存储的,这个数字也需要占用一定的字节数,因此 lengthFieldLength 就是用来标识这个数字占用多少字节的变量。

例如如下示例中,长度字段处于第 4 个位置,因此 lengthFieldOffset = 3。另外长度字段自身占用一个字节,且表示的值是:0x0A,用十进制表示就是 10,也就是消息体的长度是 10 个字节,从长度字段往后 10 个字节就是消息体的具体类容。

长度字段解码器

和行解码器和分隔符解码器类似,我们有时候希望解码出来的数据,不包含换行符或者分隔符,因此需要跳过一定的字节数后再解码数据。同样,在基于长度字段的解码器中,也会有这样类似的需求,因此 initialBytesToStrip 字段就是用来表示在解码时跳过多少个字节的数据。

通常我们发送的一串数据中,会包含消息头消息体,在有些协议中喜欢直接使用长度字段来直接表示消息体的长度;而有些协议中,喜欢用长度字段来表示整个数据的长度,即:消息头的长度 + 消息体的长度,那么这个时候,数据的接收方在接收到消息后,想要知道消息体的内容,就无能为力了。怎么办呢?那就需要另外一个字段:lengthAdjustment。这个字段翻译过来就是长度的调整值,如果长度表示的是整个消息的长度,那么将 lengthAdjustment 设置为负数,用整个消息的长度加上这个负数,那就是消息体的长度了。

示例

LengthFieldBasedFrameDecoder 的源码中,官方给出了很多示例,下面结合官方给出的示例,来解释下上面 4 个重要属性的含义吧。

示例 1

当长度字段处于数据的第一个位置,后面是消息体。长度字段占用两个字节(0x000C 这是一个 16 进制数,表示的是数值是 12,占用两个字节)。解码之后的数据如下右边所示。

lengthFieldOffset = 0
lengthFieldLength = 2
lengthAdjustment  = 0
initialBytesToStrip = 0
BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
+--------+----------------+      +--------+----------------+
| Length | Actual Content |----->| Length | Actual Content |
| 0x000C | "HELLO, WORLD" |     | 0x000C | "HELLO, WORLD" |
+--------+----------------+      +--------+----------------+
示例 2

当长度字段处于数据的第一个位置,后面是消息体。长度字段占用两个字节,由于 initialBytesToStrip = 2,因此在解码时需要跳过两个字节,所以解码之后的数据就不包含 0x000C 了,结果如下右边所示。

lengthFieldOffset   = 0
lengthFieldLength   = 2
lengthAdjustment    = 0
initialBytesToStrip = 2
BEFORE DECODE (14 bytes)         AFTER DECODE (12 bytes)
+--------+----------------+      +----------------+
| Length | Actual Content |----->| Actual Content |
| 
       在Java界,Netty无疑是开发网络应用的拿手菜。你不需要太多关注复杂的NIO模型和底层网络的细节,使用其丰富的接口,可以很容易的实现复杂的通讯功能。 本课程准备的十二个实例,按照由简单到复杂的学习路线,让你能够快速学习如何利用Netty来开发网络通信应用。                每个实例简洁、清爽、实用,重点在“用”上,即培训大家如何熟练的使用Netty解决实际问题,抛弃以往边讲应用边分析源码的培训模式所带来的“高不成低不就”情况,在已经能够熟练使用、并且清楚开发流程的基础上再去分析源码就会思路清晰、事半功倍。        本套课程的十二个实例,各自独立,同时又层层递进,每个实例都是针对典型的实际应用场景,学了马上就能应用到实际项目中去。 学习好Netty 总有一个理由给你惊喜!! 一、应用场景        Netty已经众多领域得到大规模应用,这些领域包括:物联网领域、互联网领域、电信领域、大数据领域、游戏行业、企业应用、银行证券金融领域、。。。  二、技术深度        多款开源框架中应用了Netty,如阿里分布式服务框架 Dubbo 的 RPC 框架、淘宝的消息中间件 R0cketMQ、Hadoop 的高性能通信和序列化组件 Avro 的 RPC 框架、开源集群运算框架 Spark、分布式计算框架 Storm、并发应用和分布式应用 Akka、。。。  三、就业前景         很多大厂在招聘高级/资深Java工程师时要求熟练学习、或熟悉Netty,下面只是简要列出,这个名单可以很长。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值