Netty下Google Protocol Buffer自定义编码器和解码器实现

在使用Netty加Google Protocol Buffer进行开发的时候,发现每定义一个实体类的话,对应的服务器的handler就要加上这个类的解码器,十分的麻烦,因此在自己实现协议的时候,将类型转化也加了进去。

具体的实现思路是通过继承ByteToMessageDecoderMessageToMessageEncoder<MessageLiteOrBuilder>这两个类,通过在数据报文前添加一个字节的标志位区分类的类型,在解码的时候通过判断标识生成对应的类。

具体的代码则是参照google protocol buffer自带的netty实现ProtobufEncoderProtobufVarint32FrameDecoder这两个类写的。

编码器实现
/**
 * 自定义的编码器
 * 数据包的格式
 * 包长度(4B) + 包数据类型(1B)+ 数据
 */
public class CustomEncoder extends MessageToMessageEncoder<MessageLiteOrBuilder> {

    private byte[] encodeHeader(MessageLite msg, int length) {
        byte messageType = 0x0f;//数据类型
        //定义数据的类型
        if (msg instanceof Command.Request) {
            messageType = 0x00;
        } else if (msg instanceof Command.Response) {
            messageType = 0x01;
        } else if (msg instanceof Command.Data) {
            messageType = 0x02;
        }
        //数据包头
        byte[] header = new byte[5];
        //数据长度
        int i = 0;
        //将int32的4个字节提取到数组
        for (byte b : ByteUtil.int2Bytes(length)) {
            header[i++] = b;
        }
        //数据类型
        header[4] = messageType;
        return header;
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out) throws Exception {
        byte[] body;
        byte[] header;
        if (msg instanceof MessageLite) {
            body = ((MessageLite) msg).toByteArray();
            header = encodeHeader(((MessageLite) msg), body.length);
            //写数据
            out.add(wrappedBuffer(ByteUtil.concat(header, body)));
        } else if (msg instanceof MessageLite.Builder) {
            body = ((MessageLite.Builder) msg).build().toByteArray();
            header = encodeHeader(((MessageLite.Builder) msg).build(), body.length);
            out.add(wrappedBuffer(ByteUtil.concat(header, body)));
        }
    }
}

解码器实现
public class CustomDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws InvalidProtocolBufferException {
        if (in.isReadable(5)) {
            //可以查看源码里面类的注释
            //文件操作的读写指针是分开的
            in.markReaderIndex();
            //长度
            int length = 0;
            for (int ix = 0; ix < 4; ++ix) {
                length <<= 8;
                length |= (in.readByte() & 0xff);
            }
            //类型
            byte type = in.readByte();

            //数据长度不够
            if (in.readableBytes() < length) {
                in.resetReaderIndex();
                return;
            }

            ByteBuf body = in.readBytes(length);

            byte[] array;
            int offset;

            int readableLen = body.readableBytes();
            //判断ByteBuf是否有支撑数组,如果没有则说明其是用的是直接缓存模式
            if (body.hasArray()) {
                array = body.array();
                offset = body.arrayOffset() + body.readerIndex();
            } else {
                //需要生成一个数组来保存
                array = new byte[readableLen];
                body.getBytes(body.readerIndex(), array, 0, readableLen);
                offset = 0;
            }


            switch (type) {
                case 0x00:
                    out.add(Command.Request.getDefaultInstance()
                            .getParserForType().parseFrom(array, offset, length));
                    break;
                case 0x01:
                    out.add(Command.Response.getDefaultInstance()
                            .getParserForType().parseFrom(array, offset, length));
                    break;
                case 0x02:
                    out.add(Command.Data.getDefaultInstance()
                            .getParserForType().parseFrom(array, offset, length));
                    break;
            }
        }

    }

}

最后只要添加进handler即可

 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) {
         ChannelPipeline pipeline = ch.pipeline();
         pipeline.addLast("decoder", new CustomDecoder());
         pipeline.addLast("encoder", new CustomEncoder());
     }
 })

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值