netty的粘包和拆包是很重要的一部分,粘包分如图中的几种情况
假设客户端分别发送了两个数据包,D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下情况:
服务端分别收到了D1和D2,没有粘包和拆包
服务端一次性收到了D1和D2,称为TCP粘包
服务端两次读取到了两个数据包,第一次读到了D1的完整部分和D2的部分数据,第二次读到了D2的剩余部分。 这称为TCP拆包
服务端两次读取到两个数据包,第一次是D1的部分,第二次是D1的剩余部分和D2的完整部分
也有可能D1和D2非常大,期间发生多次拆包。
netty有很多自带的拆包封装类,比如LineBasedFrameDecoder等,但是最多的还是根据自己的帧格式自定义协议来进行拆包,我们拿GB/T18657.1—2002的6.2.4条FT1.2异步式传输帧格式来举例。
格式如图
应对这种比较难的帧格式就不能用自带的拆包类,而要根据帧格式自定义解码器。
先判断枕头,再略过两字节(长度)再判断帧中间标识,再读帧尾标识。
具体代码如下
@Slf4j
public class GateWayDecoder extends ByteToMessageDecoder{
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
//bytebuf gc出错怎么解决
log.info("收到报文");
if(byteBuf == null){
log.info("收到的报文为空");
return;
}
//判断是否满足字节最小数目
if(byteBuf.readableBytes() < ProtocolConstant.FRAME_SIZE_MIN){
log.info("报文不够最小数目");
return;
}
int beginReader;
while (true) {
// 获取包头开始的index
beginReader = byteBuf.readerIndex();
// 标记包头开始的index
byteBuf.markReaderIndex(