netty 初体验 自定义解码器

本文档介绍了如何实现一个自定义的ByteToMessageDecoder,用于解析ModbusTCP协议的数据包,包括MBAP头判断、长度计算、粘包处理和消息解码。重点讲解了包头的判断逻辑和数据体的正确截取方式。
package cc.ak.tcp.codec;

//import com.zw.admin.server.utils.HexConvertUtil;
import cc.ak.utils.HexConvertUtil;
import cn.hutool.core.util.ArrayUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.internal.logging.InternalLoggerFactory;
import lombok.extern.slf4j.Slf4j;

import javax.lang.model.element.VariableElement;
import java.util.List;

/**
 * 自定义解码器
 *
 * @author jie
 */
@Slf4j
public class CustomDecoder extends ByteToMessageDecoder {

//    InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
//	我们定义的是前六位是一个包的包头  所以判断的话一般根据前六位来判断是不是我们的包,从而获取报的长度来进行截取,避免粘包
    public static final int MBAP_LEN = 6;

    public static final int MAX_LEN = 2000;

    /**
     * 十六进制字符串数组解析
     *
     * @param channelHandlerContext
     * @param in                    传入数据
     * @param list                  添加解码消息
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> list) throws Exception {
        ByteBuf copy = in.copy();
        if (copy.readableBytes() < MBAP_LEN) {
            //将消息清除掉
            in.readBytes(in.readableBytes());
            return;
        }
        //数据包过长就会将数据包丢弃

        // 标记一下当前的readIndex的位置
        int beginIndex = copy.readerIndex();
        //读取报文头MBAP
        ByteBuf buf = copy.readBytes(MBAP_LEN);
        byte[] dst = new byte[MBAP_LEN];
        buf.readBytes(dst);
        //判断是否是ModbusTCP协议
        if (dst[2] != 0x00 || dst[3] != 0x00) {
            //读取所有消息  防止消息累积
            in.readBytes(in.readableBytes());
            in.discardReadBytes();
            return;
        }
        //获取MBAP中的数据体长度
        long len = HexConvertUtil.hexByteToLong(new byte[]{dst[4], dst[5]});
        //报文长度小于数据体长度
        int readLen = copy.readableBytes();
        if (readLen < len) {
            if(len > MAX_LEN){
                //大于最大长度这个包舍弃
                in.readBytes(in.readableBytes());
                in.discardReadBytes();
            }
            //重置索引
            copy.readerIndex(beginIndex);
            System.out.println("查看未发送的字节长度"+in.readableBytes());
            return;
        }
        ByteBuf message = in.readBytes((int) (MBAP_LEN+len));
        byte[] bytes = new byte[(int) (MBAP_LEN+len)];
        message.readBytes(bytes);
        //将数组合并
        String hexMessage = ByteBufUtil.hexDump(bytes);
        log.info("接收的指令"+hexMessage);
        System.out.println("要去下一个地方了");
        list.add(hexMessage);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天予不洗头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值