专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

Netty「源码解析」之 ByteToMessageDecoder

ins518 2025-07-08 18:56:53 技术文章 1 ℃ 0 评论

前言

在之前我们将结果什么是粘包和半包, 通常情况下我们想解决这种TCP消息传输问题都会采用固定消息头或者固定长度的方式, 在Netty中当然也有相应的方法, 本章主要讲解Netty中的解码器ByteToMessageDecoder

在Netty中, 每个handler和channel都是唯一绑定的, 一个handler只对应一个channel, 所以在将channel中的数据进行解析时, 若不是一个完整的数据包则解析失败, 并将这个数据包进行保存, 等下次解析时对两个数据进行组合解析, 直到解析到完整的数据, 才会将数据包进行向下传递

本篇文章将添加于我的Netty专栏 欢迎大家关注

ByteToMessageDecoder

可以看到该类是个抽象类, 也是Netty解码器的基类, 所以我们在实际使用解码器时一般也不是直接使用的该类, 而是使用的其子类

继承实现图

通过继承实现图可以看到该类继承于ChannelInboundHandler属于入站类Handler, 是专门用来处理输入的Handler

Cumulator 累加器

在这个类最开始映入眼帘的就是两个累加器

MERGE_CUMULATOR: 通过内存拷贝把数据都放入一个ByteBuf里面

COMPOSITE_CUMULATOR: 混合存储, 相当于将ByteBuf加入到CompositeByteBuf中, 同时因为使用了更复杂的索引计算, 所以他会比MERGE_CUMULATOR更慢

channelRead() 方法

这是一个入站Handler所以我们还是主要看他的channelRead()方法

在该方法中, 流程大概如下:

  • 首先去判断这个消息是否为ByteBuf类型
  • 将变量selfFiredChannelRead设置为true, 这个变量一共调用了两次, 一次是这回的赋值, 下一次是在通道读取完成的时候调用的方法

接下来 CodecOutputList out =
CodecOutputList.newInstance();
可以理解为创建了一个List, 用于存储解析到的对象, 这个类CodecOutputList的继承实现图如下所示, 可以看到他继承了List类

然后去判断当前累加器是否为null, 如果为null, 则first == true, 代表这是第一次从IO流中读取数据, 执行cumulator.cumulate方法, 这个方法是个接口, 他的作用如下

  • first == true, 则将刚读进来的数据赋值给累加器
  • first == false, 则将累加器内的数据和当前数据进行累加

最后会执 行callDecode(ctx, cumulation, out); 进行解析

当我们执行完累加器操作之后, 会进入到finally内

在这里会进行累加器的判断, 如果累计区没有可读字节了就将numReads次数归零, 释放累计去, 等待GC

但是如果当前累加器内还有数据, 就会进行numReads++操作, 当numReads > 16时, 会将已经读过的数据进行丢弃, 同时numReads = 0

最后记录list长度, firedChannelRead |= out.insertSinceRecycled(); 这一步是判断是否已回收, 只有当firedChannelRead和out.insertSinceRecycled()均为false时为firedChannelRead == false, 其他情况均为ture

最后向下传播数据

本文内容到此结束了

如有收获欢迎点赞收藏关注,您的鼓励是我最大的动力。

作者:宁轩
链接:
https://juejin.cn/post/7179755582218305591

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表