最近学习了Netty ByteToMessageDecoder

背景:项目要接 JTT808(2013)道路运输车辆卫星定位系统北斗兼容车载终端通讯协议技术规范协议(808部标2013) 和1070视频协议,另外 加 苏标 ”主动安全“以及苏标附件服务器。

最近学习了Netty ByteToMessageDecoder_第1张图片

技术选型:netty作为tcpserver端技术框架

1:netty自身提供方便的解码器工具类(如下),“快速和简单” 开发(满足信令标识位解析)

  • 定长——FixedLengthFrameDecoder
  • 分隔符——DelimiterBasedFrameDecoder
  • 基于长度的变长包——LengthFieldBasedFrameDecoder

 2:因为存在码流上传,会涉及到分包问题 netty自身提供了ByteToMessageDecoder 扩展类很方便进行自定义协议扩展

  • 苏标中:报警是通过扩展部标JT808协议0x0200位置上报的附加数据上报的,平台判断附件数量大于0,则下发苏标0x9208附件上传指令让终端把证据文件发到附件服务器。而且在附件服务器中的协议使用了2种:(1) 0x1210报警附件信息消息、0x1211文件信息上传、0x1212文件上传完成消息采用部标JT808协议。(2) 文件数据上传采用苏标自定义的格式。因此柔和了 “信令”+“码流”两种数据包格式 需要自定义解析,单纯依靠提供解码器不能处理
  • 附件服务器采用ByteToMessageDecoder扩展协议:其码流超过1024byte netty底层会分多次调用decode方法,要自己积累byte形成一个整包 再往下层 channelRead里传递

 问题难点:

用netty自定义解码器 ByteToMessageDecoder,协议信令(7Exxx7E)  还有码流的标识(0x30316364) 当码流长度很大的时候,还要 解决读半包的问题一次接收 1024byte。如何直到读到完整的数据才进行处理。而且每次收到的数据怎么去判断是不是和上一个数据是连续的,如何在没有收集到完整数据时不处理数据而继续接受呢?这是我一直困扰的问题。因为我把每一个byteBuf当成一个message来想了,其实不是的,ByteBuf中有两个指针readIndex和writeIndex,readIndex永远小于writeIndex。大概如下图所示

最近学习了Netty ByteToMessageDecoder_第2张图片

转载ByteBuf示例图

 

在netty的设计中ByteBuf是可以被重用的,所以可能针对这一个ChannelRead一直读取的是同一个ByteBuf。这其中readrIndex之前的是已经读取过的,就是已经被调用readXXX()之后的数据,可以重新去读取,readerIndex和writerIndex之前的是当前的readableBytes,writerIndex到capacity的是writeableBytes,当writerIndex超过capacity时就会扩展。同时为了重用这部分空间,当调用discardBytes时,会把readerIndex和writerIndex拷贝到开头,这样前面废弃的部分就被重用了,也一定程度场避免了扩容,节省了空间。

那如何针对上面的输入写ByteBuf的解码呢?
先看看netty自带的解码器怎么解决这个问题,其中LengthFieldBasedFrameDecoder就是用来解决这一类的问题的。在李林峰的文章中有详细介绍,这里就不赘述了。

 

//TODO 协议还在进一步完善中,此次仅开发苏标主动安全,JT1078视频还没开始。。。待续

0802补充:* 附件服务器 因即存在808信令又存在码流 所以 自定义解码器(补充码流协议消息体中7E不做转义) JT1078DelimiterDecoder

如果出现netty IndexOutOfBoundsException: readerIndex(1348) + length(1) exceeds writerIndex

这种就是你的解码器那块有问题,你在处理粘包拆包的时候没有把已读字节清除干净,可能是你read***字节数据后,用了markReaderIndex()和resetReaderIndex(),但是resetReaderIndex()的时候定位不正确。

 


参考网上总结:

总结了8中decode可能使用场景:https://vimsky.com/examples/detail/java-method-io.netty.buffer.ByteBuf.markReaderIndex.html

并发编程网的http://ifeve.com/netty5-user-guide/

这个哥们写的有点复杂,他为了把分包的数据合并一个整包,再decode里新建了map用来存储netty每次调用时传来的数据:https://www.gcssloop.com/gebug/netty-private-protocol

netty 快速入门

https://www.gcssloop.com/gebug/netty-private-protocol

你可能感兴趣的:(最近学习了之,netty,netty)