Netty自定义解码器解决粘包、数据异常读取等问题

时间:2024-04-08 18:36:06

Netty自定粘包解码器

netty粘包处理
netty提供了多种编码器用于处理半包,这些编码器包含
LineBasedFrameDecoder 换行解码器
DelimiterBasedFrameDecoder 分隔符解码器
FixedLengthFrameDecoder 定长解码器

各种解码器使用场景此处就不做介绍,想了解的可以自行官网或者google
基于自定义协议的解码器其实可以根据DelimiterBasedFrameDecoder来实现,但是这个解码器在实际使用中不是那么合适.有如下几个场景:

  1. 16进制的自定义协议
  2. 现有解码器无法满足的场景
  3. DelimiterBasedFrameDecoder 自定义分包符分包异常,数据读取异常等

在前段时间因为对DelimiterBasedFrameDecoder不太了解,结果把自己给坑了把
和硬件同事(C语言大佬)根据使用场景定了个协议包,包头以0XFF 0XFE开头 XXX结尾
大致协议是这样的
整体报文: 包头+报体+校验位(crc)
包头两个字节: 0XFF 0XFE
报体: N个字节
校验位: 2个字节
简单来讲就是要通过0XFF 0XFE来分包,碰到这两个字节在一起就一刀两半,校验位不是重点此处忽略
在使用DelimiterBasedFrameDecoder 的使用遇到问题如下:

1.分包异常
2.数据脏读

具体代码如下:
配置DelimiterBasedFrameDecoder解码器,最大长度1024,使用0xff 0xfe分包在handler里打印出结果

Netty自定义解码器解决粘包、数据异常读取等问题
Netty自定义解码器解决粘包、数据异常读取等问题

启动服务端,启动模拟客户端发送数据
FF FE 11 22 33 FF FE 44 55 66

Netty自定义解码器解决粘包、数据异常读取等问题

第一次连接并发送数据输出结果如下:

Netty自定义解码器解决粘包、数据异常读取等问题
数据只有一半?那再来发送一次同样的数据看看
Netty自定义解码器解决粘包、数据异常读取等问题
第二次输出就对了 是不是很诡异? 试了几次只要传输的内容改变这个问题就会出现
换个思路想想有没可能是分隔符放置的问题? 那我们来试试
客户端的发送数据改为
11 22 33 FF FE 44 55 66 FF FE 77 88 FF FE

输出结果如下
Netty自定义解码器解决粘包、数据异常读取等问题

哈哈,第一次连接发送数据和第二次发送输出结果都没有问题 到这里是不是结束了?答案当然是 没有
那我们再试试这种场景
客户端的发送数据改为
11 22 33 FF FE 44 55 66 FF FE 77 88 FF FE 99 00

两次输出结果如下:
Netty自定义解码器解决粘包、数据异常读取等问题

WTF???
这种方式必然是不行的,至于为什么会出现这个问题有性趣的可以去看下DelimiterBasedFrameDecoder中的decode逻辑
那这个问题怎么解决呢
鄙人不才没能在DelimiterBasedFrameDecoder的基础上解决这个问题,只有另辟新路自定义解码器
查看DelimiterBasedFrameDecoder是继承ByteToMessageDecoder(大多数解码器都是这个类的派生类)主要是实现decode方法 那我们可以依葫芦画瓢

Netty自定义解码器解决粘包、数据异常读取等问题
Netty自定义解码器解决粘包、数据异常读取等问题

新建个类继承ByteToMessageDecoder实现decode抽象方法
Netty自定义解码器解决粘包、数据异常读取等问题

然后自己实现decode方法,大致实现如下

Netty自定义解码器解决粘包、数据异常读取等问题

Netty自定义解码器解决粘包、数据异常读取等问题

测试验证

根据上面的3种场景,客户端发送的数据依次为
FF FE 11 22 33 FF FE 44 55 66

结果
Netty自定义解码器解决粘包、数据异常读取等问题

11 22 33 FF FE 44 55 66 FF FE 77 88 FF FE
结果
Netty自定义解码器解决粘包、数据异常读取等问题

11 22 33 FF FE 44 55 66 FF FE 77 88 FF FE 99 00
结果

Netty自定义解码器解决粘包、数据异常读取等问题

如果对于第二和第三种前面没有以0xff 0xfe开头的数据也想保留的话则需在decode逻辑里把firstHead设置默认为true就可以了

Netty自定义解码器解决粘包、数据异常读取等问题
好了鄙人技术有限 目前想到的解决方案只有这么多,如果有更好方案的大佬或者上面有误的地方万望不吝赐教o(∩_∩)o 哈哈

自己选的路,跪着也要走完,

Netty自定义解码器解决粘包、数据异常读取等问题