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