欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入了解Netty:高级内置解码器、编码器和ByteBuf

最编程 2024-01-14 14:17:57
...
  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("\n".getBytes());  // 沾包 分割符 \n
    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数据为空或满的情形,作为数据容器,要存在边界值检查,确保读写安全。