Netty「源码解析」之 ByteToMessageDecoder

Netty「源码解析」之 ByteToMessageDecoder

「我正在参与掘金会员专属活动-源码共读第一期,点击参与

前言

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

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

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

ByteToMessageDecoder

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

image.png

继承实现图

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

image.png

Cumulator 累加器

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

image.png

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

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

channelRead() 方法

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

image.png

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

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

image.png

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

image.png

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

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

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

image.png

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

image.png

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

image.png

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

image.png

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

最后向下传播数据

image.png




本文内容到此结束了

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

如有错误❌疑问💬欢迎各位大佬指出。

我是 宁轩 , 我们下次再见

分类:
后端