「我正在参与掘金会员专属活动-源码共读第一期,点击参与」
前言
在之前我们将结果什么是粘包和半包, 通常情况下我们想解决这种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
最后向下传播数据
本文内容到此结束了
如有收获欢迎点赞👍收藏💖关注✔️,您的鼓励是我最大的动力。
如有错误❌疑问💬欢迎各位大佬指出。
我是 宁轩 , 我们下次再见