BtyeBuf读操作 - netty

半兽人 发表于: 2018-04-26   最后更新时间: 2018-04-26 16:47:22  
{{totalSubscript}} 订阅, 5,016 游览

在进行netty的开发中,需要对数据进行编解码

netty 提供的解码器

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

netty 提供的编码器

  • Base64Encoder base64编码器
  • StringEncoder 消息转成String编码器
  • LineBasedFrameDecoder 自动完成标识符分隔编码器
  • MessageToMessageEncoder 根据 消息对象 编码为消息对象

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

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数据为空或满的情形,作为数据容器,要存在边界值检查,确保读写安全。

DelimiterBasedFrameDecoder 解决TCP的粘包解码器

IODecoder 继承

/**
 * 解码
 * DelimiterBasedFrameDecoder  防止沾包
 */
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);
    }
}

MessageToMessageEncoder 编码器

/**
 * 指令 编码 
 * MessageToMessageEncoder<PushEntity>
 * 把 PushEnty 编码为string
 */
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();

        }
    }
}

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();
            }
        }
    }
更新于 2018-04-26

查看netty更多相关的文章或提一个关于netty的问题,也可以与我们一起分享文章