Netty「实战」之实现自定义解码器

4,161 阅读3分钟

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

前言

在上一章 Netty「源码解析」之 ByteToMessageDecoder - 掘金 (juejin.cn)中我们学习了ByteToMessageDecoder的相关源码, 以及消息的读取, 本篇文章就去看看Netty是怎么实现一个定长的消息解码器

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

常用解码器

之前我们就讲过, TCP连接传输数据容易产生粘包半包的情况, 我们为了解决这种问题通常会对消息进行一些区分, 或者说统一格式:

  • 特殊分隔符: 将特殊分隔符作为消息结束的标志, 例如: 回车符
  • 固定消息长度: 将消息长度固定, 例如: 每条消息的长度固定为8
  • 固定消息头: 所有消息的消息头相同, 根据消息头来区分是否同属一条消息
  • 复杂消息: 通常情况下, 我们会采用上述多个情况, 例如: 固定消息头, 消息中固定某个字节为当前消息的长度, 固定消息长度, 不足的地方填 0等

针对这种情况Netty给出了相应的解码器, 这些解码器继承于ByteToMessageDecoder基类, 同时为我们实现了多种针对不同情况的解码器, 常用解码器如下所示:

  • LineBasedFrameDecoder - 换行解码器
  • DelimiterBasedFrameDecoder - 分隔符解码器
  • FixedLengthFrameDecoder - 定长解码器
  • LengthFieldBasedFrameDecoder - 消息头定长解码器

image.png

FixedLengthFrameDecoder

我们这边只使用定长解码器的方式去测试, 其他类型请大家自行测试

代码来自于 源码共读」 可以直接git下述代码

git clone https://github.com/arthur-zhang/netty-study.git

我们直接在我们的启动配置类MyServer当中对pipeline进行相应的配置, 具体如下所示, FixedLengthFrameDecoder构造参数就是定长的值, 为 8, 具体源代码我们后续在进行分析

image.png

测试粘包

然后启动我们的MyServer之后使用连接工具进行连接, 并发送测试消息(粘包), 消息内容为0123456789abcdef

image.png

同时, 我们可以查看控制台输出, 如下所示, 通过绿框可以看到每个消息分别是读还是写, 通过黄框可以看到具体的消息内容, 可以看到, 我们传输的消息被根据定长来切割成了两条消息

image.png

测试半包

本次测试模拟半包情况, 先是发送0123, 第二次发送456789abcdef, 同时我们查看控制台打印, 他先是进行了两次写入, 由于第一次读取的长度不足我们设置的 8 , 所以没有写入操作, 直到第二次的消息传递将两次消息进行了累加操作之后在进行了拆分

image.png

FixedLengthFrameDecoder 源码分析

构造方法

在之前, 我们是通过构造方法来对消息设置的定长, 那么我们就从构造方法开始分析

首先可以看到该类的构造方法东西很简单, checkPostitive()方法是用来检测参数是否正确的, 毕竟消息长度不能小于等于零, 然后就是给该类的属性frameLength进行赋值

image.png

checkPostitive()方法代码如下所示

image.png

decode

我们都知道解码的方法实现都是在decode()方法中, 那么我们就看一下该方法

可以看到该方法的代码行数也是很少的, 下面那个decode()方法就是判断当前消息的长度是否大于我们在构造函数设置的消息定长frameLength

  • 大于返回我们消息内容, 返回长度为 frameLength, 我们设置的 8
  • 不大于就不做处理, 等待下一次消息进行累加

image.png




本文内容到此结束了

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

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

我是 宁轩 , 我们下次再见