目录
4.3 ByteToMessageDecoder#channelRead
1.协议说明
Netty框架是基于Java NIO框架,性能彪悍,支持的协议丰富,广受Java爱好者亲莱,支持如下协议
- TCP/UDP:Netty提供了基于NIO的TCP和UDP编程框架,可以用来构建高性能、高可用性的网络应用。
- HTTP/HTTPS:Netty提供了HTTP/HTTPS编程框架,可以用来开发Web服务器和客户端。
- WebSocket:Netty提供了WebSocket编程框架,可以用来实现双向通信应用程序,如聊天室等。
- SPDY/HTTP2:Netty提供了SPDY和HTTP2编程框架,可以用来实现高效的Web应用程序。
- MQTT/CoAP:Netty提供了MQTT和CoAP编程框架,可以用来构建IoT应用程序。
我们在基于Netty框架开发过程中往往需要自定义私有协议,如端到端的通信协议,端到平台数据通信协议,我们需要根据业务的特点自定义数据报文格式,举例如下:
| 帧头 | 版本 | 命令标识符 | 序列号 | 设备编码 | 帧长 | 正文 | 校验码 |
|---|---|---|---|---|---|---|---|
| 1byte | 1byte | 1byte | 2byte | 4byte | 4byte | N个byte | 2byte |
假如我们定义了上述私有协议的TCP报文,通过netty框架发送和解析
发送端:某类通信设备(client)
接收端:Java应用服务(Server)
本节我主要分析一下server端解析报文的一个过程,client当然也很重要,尤其在建立TCP连接和关闭连接需要严格控制,否则服务端会发现大量的CLOSE_WAIT(被动关闭连接),甚至大量TIME_WAIT(主动关闭连接),关于这个处理之前的文章有讲解。
本节Server端是基于Netty版本:netty-all-4.1.30.Final
本节源码分析需求就是要解析一个自定义TCP协议的数据报文进行解码,关于编码解码熟悉网络编程的同学都明白,不清楚的可以稍微查阅一下资料有助于学习为什么要解码以及如何解码。本节不会对具体报文的解析做具体讲解,只对Netty提供的解码器基类ByteToMessageDecoder做一下源码分解,以及如何使用ByteToMessageDecoder开发属于自己的Decoder,接下来我们看看ByteToMessageDecoder的定义。
/*继承ChannelInboundHandlerAdapter
* 字节到消息的编码器,是Inbound操作,这类解码器处理器都不是共享的,因为需要存没有
* 解码完的数据,还有各种状态,是独立的,不能进行共享。
* 所以在pipeline上需要每次创建新的对象,不是能够进行对象复用。
*/
public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter {
}
2.类的实现
解码器的ByteToMessageDecoder ,该类继承了ChannelInboundHandlerAdapter ,ChannelInboundHandlerAdapter继承ChannelHandlerAdapter,
ChannelInboundHandlerAdapter实现ChannelInboundHandler接口,也就是说ChannelInboundHandler定义了解码器需要处理的工作(方法)

ChannelInboundHandlerAdapter是一个适配器模式,负责Decoder的扩展。它的实现有很多,简单列举一下:
-
HeartBeatHandler
-
MessageToMessageDecoder
-
SimpleChannelInboundHandler(实现抽象了channelRead方法,提供抽象方法channelRead0)
ByteToMessageDecoder。。。。。。
以上都是比较常用的Decoder或Handler,基于这些基类还定义了很多handler,有兴趣的同学可以跟代码查阅。
3.Decoder工作流程
每当数据到达Server端时,SocketServer通过Reactor模型分配具体的worker线程进行处理数据,处理数据就需要我们的事先定义好的Decoder以及handler,假如我们定义了以下两个对象:
- MyDecoder extends
ByteToMessageDecoder{} 作为解码器 MyHandler extendsSimpleChannelInboundHandler{} 作为解码后的业务处理器
worker线程——〉MyDecoder#channelRead实际就是调用ByteToMessageDecoder#channelRead——〉Cumulator累加器处理——〉
解码器decode处理(MyDecoder需要实现decode方法)——〉Myhandler#channelRead0处理具体的数据(msg),msg是通过MyDecoder#decode方法解码后的数据对象。
4.源码解析
4.1 累加器Cumulator(数据累加缓冲区)
累加器Cumulator的作用是数据累加缓冲区,解决tcp数据包中出现半包和粘包问题。
半包:接收到的byte字节不足一个完整的数据包,
半包处理办法:不足一个完整的数据包先放入累加器不做解码,等待续传的数据包;
粘包:接收到的byte字节数据包中包括其他数据包的数据(靠数据包协议中定义的帧头帧尾标识来识别,多于1个以上的帧头或帧尾数据包为粘包数据),
粘包处理办法:按照数据包帧结构定义去解析,需要结合累加器,解析完一个数据包交给handler去处理,剩下的不足一个数据包长度的字节保存在累加器等待续传的数据包收到之后继续解码。
ByteToMessageDecoder内部定义了Cumulator接口
/**

本文详细介绍了在Netty框架中如何解析自定义TCP协议数据报文,重点关注ByteToMessageDecoder的工作原理、累加器Cumulator的作用以及如何开发和使用自定义Decoder处理半包和粘包问题。
最低0.47元/天 解锁文章
778

被折叠的 条评论
为什么被折叠?



