TCP通信中的数据包解析(处理拆包粘包)

这个解码器最主要是解决TCP粘包拆包问题

package com.wunaozai.iot.nettyplatform.code;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

/**
 * 自定义协议解析
 * @author Administrator
 *
 */
public class SmartIotDecoder extends ByteToMessageDecoder {


    private static final Logger log = LoggerFactory.getLogger(SmartIotDecoder.class);

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
        log.debug("启动解码器...");
        log.debug("目前数据缓存大小: " + buffer.readableBytes());
        // 刻度长度必须大于基本最小长度
        if(buffer.readableBytes() >= SmartIotProtocol.MIN_LEN){
            log.debug("符合最小长度,进行解析");
            //防止socket字节流攻击、客户端传来的数据过大,这里需要对数据进行过滤掉
            if(buffer.readableBytes() >= 4096){
                buffer.skipBytes(buffer.readableBytes());
                return ;
            }

            //记录包头开始位置
            int beginReader = 0;
            while(true){
                beginReader = buffer.readerIndex(); //记录包头开始位置
                buffer.markReaderIndex(); //标记包头开始index
                //读取协议开始标志
                if(buffer.readShort() == SmartIotProtocol.START){
                    break; //如果是开始标记,那么就结束查找
                }

                //如果找不到包头,这里要一个一个字节跳过
                buffer.resetReaderIndex();
                buffer.readByte();

                //当跳过后,如果数据包又不符合长度的,结束本次协议解析
                if(buffer.readableBytes() < SmartIotProtocol.MIN_LEN){
                    return ;
                }
            }

            short flowid = buffer.readShort();
            byte version_major = buffer.readByte();
            byte version_minor = buffer.readByte();
            byte second = buffer.readByte();
            byte minute = buffer.readByte();
            byte hour = buffer.readByte();
            byte day = buffer.readByte();
            byte month = buffer.readByte();
            byte year = buffer.readByte();
            byte[] src = new byte[6];
            src[0] = buffer.readByte();
            src[1] = buffer.readByte();
            src[2] = buffer.readByte();
            src[3] = buffer.readByte();
            src[4] = buffer.readByte();
            src[5] = buffer.readByte();
            byte[] dest = new byte[6];
            dest[0] = buffer.readByte();
            dest[1] = buffer.readByte();
            dest[2] = buffer.readByte();
            dest[3] = buffer.readByte();
            dest[4] = buffer.readByte();
            dest[5] = buffer.readByte();
            short data_len = buffer.readShort();
            if(buffer.readableBytes() < data_len + 4){
                //还原读指针
                buffer.readerIndex(beginReader);
                return ;
            }
            byte cmd = buffer.readByte();
            byte[] data = null;
            if(data_len > 0){
                //读取应用数据单元
                data = new byte[data_len];
                buffer.readBytes(data);
            }

            byte checksum = buffer.readByte();
            short end = buffer.readShort();

            if(end == SmartIotProtocol.END){
                log.debug("完成解析,并输出.");
                SmartIotProtocol iot = new SmartIotProtocol();
                iot.setFlowid(flowid);
                iot.setVersion_major(version_major);
                iot.setVersion_minor(version_minor);
                iot.setSecond(second);
                iot.setMinute(minute);
                iot.setHour(hour);
                iot.setDay(day);
                iot.setMonth(month);
                iot.setYear(year);
                iot.setSrc(src);
                iot.setDest(dest);
                iot.setData_len(data_len);
                iot.setCmd(cmd);
                if(data_len > 0){
                    iot.setData(data);
                }else{
                    iot.setData(null);
                }
                iot.setChecksum(checksum);
                out.add(iot);
            }
        }
    }

}

原文地址:https://www.cnblogs.com/wunaozai/p/11403015.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NettyTCP粘包拆包问题是由于底层的TCP协议无法理解上层的业务数据而导致的。为了解决这个问题,Netty提供了几种解决方案。其,常用的解决方案有四种[1]: 1. 固定长度的拆包器(FixedLengthFrameDecoder):将每个应用层数据包拆分成固定长度的大小。这种拆包器适用于应用层数据包长度固定的情况。 2. 行拆包器(LineBasedFrameDecoder):将每个应用层数据包以换行符作为分隔符进行分割拆分。这种拆包器适用于应用层数据包以换行符作为结束符的情况。 3. 分隔符拆包器(DelimiterBasedFrameDecoder):将每个应用层数据包通过自定义的分隔符进行分割拆分。这种拆包器适用于应用层数据包以特定分隔符作为结束标志的情况。 4. 基于数据包长度的拆包器(LengthFieldBasedFrameDecoder):将应用层数据包的长度作为接收端应用层数据包的拆分依据。根据应用层协议包含的数据包长度进行拆包。这种拆包器适用于应用层协议包含数据包长度的情况。 除了使用这些拆包器,还可以根据业界主流协议的解决方案来解决粘包拆包问题[3]: 1. 消息长度固定:累计读取到长度和为定长LEN的报文后,就认为读取到了一个完整的信息。 2. 使用特殊的分隔符:将换行符或其他特殊的分隔符作为消息的结束标志。 3. 在消息头定义长度字段:通过在消息头定义长度字段来标识消息的总长度。 综上所述,Netty提供了多种解决方案来解决TCP粘包拆包问题,可以根据具体的业务需求选择合适的解决方案[1][3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值