netty自定义协议解码

继承ByteToMessageDecoder类复写decode方法,项目中的一段解码规则如下:

1、服务端接收报文分为两种类型,单帧包:head为20字节,多帧包:head为24字节。字节位置:5

2、表示报文体长度字段为2个字节,字节开始位置:18

3、先读取一次buffer(缓存区),查看长度是否大于20,小于20指针回滚不作处理,等待下次读取,如果

      大于20,取出帧类型字段判断是否为多帧包,再取出报文体长度,如果为多帧包,则包体长度加4,最后

      截取包头加包体的长度报文,返回完整的一个包;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

public class MsgPackDecode extends ByteToMessageDecoder{
    private static int FRAMETYPE_OFFSET = 5;//帧类型字节位置
    private static int HEAD_LENGHT = 20;//单帧包头部长度 如果为多帧包为24
    private static int bodyStartPos = 18;//包体长度标识起始位置
    private static int LENGHT_OFFSET = 2;//包体长度标识长度
    private static ByteBuf buf = Unpooled.buffer();//创建一个ByteBuf缓存区
    private static java.util.concurrent.atomic.AtomicInteger  c = new AtomicInteger(1);
     @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in,
            List<Object> out) throws Exception {
        Object o = decode(ctx, in);
        if (o != null) {
            out.add(o);
            System.err.println(c.getAndIncrement());
        }
    }
    
     //自定义协议解码
     private Object decode(ChannelHandlerContext ctx, ByteBuf in) {
             //标记读指针位置,以便可以回滚指针
            in.markReaderIndex();
            
            //如果读取的包长度不够head_length,回滚指针不做处理,等待下个包再解析
            if(in.readableBytes() < HEAD_LENGHT){
                in.resetReaderIndex();
                return null;
            } else {
                //读取包头中帧类型(0:单帧包1:多帧包)信息
                in.readBytes(buf, HEAD_LENGHT);
                byte[] req = new byte[buf.readableBytes()];
                buf.readBytes(req);
                //判断帧类型(0:单帧包1:多帧包)
                int frameType = (req[FRAMETYPE_OFFSET] & 0x04) == 0x04 ? 1 : 0;//获取帧类型
                int bodylenght = byteToint(subBytes(req,bodyStartPos,LENGHT_OFFSET));//获取体长度
                
                if(frameType==0){
                    //单帧包
                    // 如发现剩余字节不够包体长度,回滚指针,等待下次解码
                    if (in.readableBytes() < bodylenght) {
                        in.resetReaderIndex();
                        return null;
                    }
                    in.readBytes(buf, bodylenght);
                    ByteBuf frame = ctx.alloc().buffer(HEAD_LENGHT + bodylenght);
                    frame.writeBytes(buf, 0, HEAD_LENGHT + bodylenght);
                    buf.clear();
                    return frame;
                }else {
                    //多帧包
                    // 如发现剩余字节不够包体长度,回滚指针,等待下次解码
                    if (in.readableBytes() < bodylenght+4) {
                        in.resetReaderIndex();
                        return null;
                    }
                    in.readBytes(buf, bodylenght+4);
                    ByteBuf frame = ctx.alloc().buffer(HEAD_LENGHT + bodylenght+4);
                    frame.writeBytes(buf, 0, HEAD_LENGHT + bodylenght+4);
                    buf.clear();
                    return frame;
                }
            }
        }

     /**
         * 从一个byte[]数组中截取一部分
         * @param src
         * @param begin
         * @param count
         * @return
         */
        public static byte[] subBytes(byte[] req, int begin, int count) {
            byte[] bs = new byte[count];
            for (int i=begin; i<begin+count; i++) bs[i-begin] = req[i];
            return bs;
        }
        
        /**
         * 字节转int
         * @param src
         * @param begin
         * @param count
         * @return
         */
        public static int byteToint(byte[] res) {   
            // 一个byte数据左移24位变成0x??000000,再右移8位变成0x00??0000   
            int targets = (res[0] << 8 & 0xFF00) | (res[1] & 0xFF);
            return targets;   
        }
}


这种方式是为了解决自定义协议tcp粘包的问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值