• Netty——高级内置解码器、编码器、ByteBuf


    netty通讯需要对数据进行编码,解码,于是我们需要用到netty的编码器、解码器

     

    netty 提供的解码

      DelimiterBasedFrameDecoder 解决TCP的粘包解码
      StringDecoder              消息转成String解码
      LineBasedFrameDecoder      自动完成标识符分隔解码
      FixedLengthFrameDecoder    固定长度解码器,二进制
      Base64Decoder base64       解码

    netty 提供的编码器
       Base64Encoder  base64编码
      StringEncoder  消息转成String编码
      LineBasedFrameDecoder  自动完成标识符分隔编码

      MessageToMessageEncoder 根据 消息对象 编码为消息对象


    对于 netty的数据传递都是ByteBuf,我们一般重写以上的解码器、编码器来实现自己的逻辑


    1、DelimiterBasedFrameDecoder 解决TCP的粘包解码器
    IODecoder  继承 
    /**
     * 解码
     * DelimiterBasedFrameDecoder  防止 沾包
     * @author flm 
     * 2017年10月30日
     */
    public class IODecoder extends DelimiterBasedFrameDecoder {
    
        public static final AttributeKey<DeviceSession> KEY = AttributeKey.valueOf("IO"); // 保存
        private static final Logger log = Logger.getLogger(IODecoder.class);
    
        // 防止 沾包 分隔符
        private static ByteBuf delimiter = Unpooled.copiedBuffer("
    ".getBytes());  // 沾包 分割符 
    
        private static int maxFrameLength = 1024 * 6;                   //数据大小
    
        
        
        public IODecoder() {
            super(maxFrameLength, delimiter);
        }
    
        /**
         * 重新 自定义解码
         */
        @Override
        protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
            // 对数据  buffer 解码
            return super.decode(ctx, buffer);
        }
    }

    2、MessageToMessageEncoder   编码器

    /**
     * 指令 编码 
     * MessageToMessageEncoder<PushEntity>
     * 把 PushEnty 编码为string
     * @author flm
     * 2017年11月3日
     */
    public class IOEncoder extends MessageToMessageEncoder<PushEntity> {
    
        private static final Logger LOG = Logger.getLogger(IOEncoder.class);
    
        
        public IOEncoder() {
            super();
        }
        
        
        /**
         * 重写 编码
         */
        @Override
        protected void encode(ChannelHandlerContext ctx, PushEntity msg, List<Object> out) throws Exception {
            try {
            PushEntity push = (PushEntity) msg;
    
                }
        
                // 以字符串 形式 发送
                out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg.toString()), Charset.defaultCharset()));
                
                
            } catch (Exception e) {
                
                e.printStackTrace();
                
            }
        }
    }
        

    3、 FixedLengthFrameDecoder 固定长度解码器,二进制

    /** 
     *  
     * 功能描述:协议消息解码器  
    * 把 btyeBuf 转为 RootMessage对象 *
    */ public class GT06MsgDecoder extends LengthFieldBasedFrameDecoder { public GT06MsgDecoder() { super(65540, 2, 1, 2, 0); //继承 }

      /*
      * 重写 解码
      */ @Override
    public Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { ByteBuf frame = (ByteBuf) super.decode(ctx, in);
         // 读取 ByteBuf 是根据 位数来读取的
    try { if (frame == null) { return null; } int frameLen = frame.readableBytes(); // 起始位 byte[] header = new byte[GT06Constant.START_DELIMITER_LEN]; frame.readBytes(header); // 是否是0x79 0x79 开头的扩展包 boolean extPacket = false; if(Arrays.equals(GT06Constant.PACKET_START_EXT, header)) { extPacket = true; } int contentLen = MessageUtils.getContentLen(frameLen, extPacket); // 跳过包长度 frame.skipBytes(MessageUtils.getPacketSizeLen(extPacket)); // 消息内容 byte[] msgContent = new byte[contentLen]; // 消息序列号 byte[] sequence = new byte[GT06Constant.MESSAGE_SERIAL_LEN]; // crc校验码 byte[] crc = new byte[GT06Constant.CRC_ITU_LEN]; // 终止符 byte[] endDelimiter = new byte[GT06Constant.END_DELIMITER_LEN];
         
    return new RootMessage(action, sequence, msgContent); } finally { if(frame != null) { frame.release(); } } }

    其它的编码器,解码器都大同小异,不懂的可以看源码




    其实解码、编码,最最重要的是对BtyeBuf的读取

     

    BtyeBuf读操作主要提供以下功能:

    • readByte:取1字节的内容;
    • skipBytes: 跳过内容
    • readUnsignedByte:取1字节的内容,返回((short) (readByte() & 0xFF));(能把负数转换为无符号吗?)
    • readShort:取2字节的内容,返回转换后的short类型;
    • readUnsignedShort:取2字节的内容,返回readShort() & 0xFFFF
    • readMedium:取3字节的内容,返回转换后的int类型;
    • readUnsignedMedium:取3字节的内容,返回转换后的int类型;
    • readInt:取4字节的内容;
    • readUnsignedInt:取4字节的内容,返回readInt() & 0xFFFFFFFFL
    • readLong:取8字节的内容;
    • readChar:取1字节的内容;
    • readFloat:取4字节的int内容,转换为float类型;
    • readDouble:取8字节的long内容,转换为double类型;
    • readBytes:取指定长度的内容,返回ByteBuf类型;
    • readSlice:取指定长度的内容,返回ByteBuf类型;
    • readBytes:取指定长度的内容到目标容器。

     写操作

    写操作提供的功能主要是往ByteBuf中写入byte内容,不再一一赘述。主要区别在于写入前根据类型转换为相对应长度的byte数组。

    主要函数是:writeBoolean、writeByte、writeShort、writeMedium、writeInt、writeLong、writeChar、writeFloat、writeDouble、writeBytes、writeZero。

    边界值安全

    不论读或写,肯定会存在ByteBuf数据为空或满的情形,作为数据容器,要存在边界值检查,确保读写安全。

     
  • 相关阅读:
    云原生范式转变:您准备好了吗?
    CentOS 6.x 开机 自启动 脚本
    忠告 程序员 先思考再编程,累的时候不要写代码
    服务化架构组件清单
    代码自动修复
    选择塑造人生
    mariadb change password
    Spring 集成 Druid Monitor URL 配置转义问题(xml or properties)
    挣钱 vs. 花钱
    管理的要义
  • 原文地址:https://www.cnblogs.com/lemon-flm/p/7813854.html
Copyright © 2020-2023  润新知