Netty(十二) Netty自定义protobuf编解码器

Netty自定义protobuf编解码器

Netty使用protobuf作传输,Netty内部已经实现默认的Netty编解码器,在Java服务和客户端之间调用是没问题,如果项目有异构语言的客户端连接Netty服务,使用protobuf作传输,那么Netty的默认编解码器就不适用了。这里自定义了编解码器。这里还有一点问题,自定义的协议头可能存在不同语言大小端的问题,想到的解决办法就是将协议头也作成一个protobuf就能解决了。

协议头
为防止粘包,在protobuff上层添加一层交互协议,每个protobuff包前面加六个字节的协议头定义。其中0-3 表示一个int类型protobuff字节大小,4为保留字段,5为数据类型。

0 1 2 3 4 5
0-8位 9-16位 17-24位 25-32位 保留字段 数据类型

package com.iscas.optocon.distribute.nettyserver.handler;

import com.google.protobuf.MessageLite;
import com.iscas.optocon.protobuf.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.ReferenceCountUtil;

import java.util.List;

/**
 * //TODO
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2018/7/21 21:31
 * @since jdk1.8
 */
public class CustomProtobufDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        while (in.readableBytes() > 6) { // 如果可读长度小于包头长度,退出。
            in.markReaderIndex();

            // 获取包头中的body长度
            byte l0 = in.readByte();
            byte l1 = in.readByte();
            byte l2 = in.readByte();
            byte l3 = in.readByte();
            int s0 = (int) (l0 & 0xff);
            int s1 = (int) (l1 & 0xff);
            int s2 = (int) (l2 & 0xff);
            int s3 = (int) (l3 & 0xff);
            s1 <<= 8;
            s2 <<= 16;
            s3 <<= 24;
            int length = (int) (s0 | s1 | s2 | s3);

            // 获取包头中的protobuf类型
            in.readByte();
            byte dataType = in.readByte();

            // 如果可读长度小于body长度,恢复读指针,退出。
            if (in.readableBytes() < length) {
                in.resetReaderIndex();
                return;
            }

            // 读取body
            ByteBuf bodyByteBuf = in.readBytes(length);

            byte[] array;
            int offset;

            int readableLen= bodyByteBuf.readableBytes();
            if (bodyByteBuf.hasArray()) {
                array = bodyByteBuf.array();
                offset = bodyByteBuf.arrayOffset() + bodyByteBuf.readerIndex();
            } else {
                array = new byte[readableLen];
                bodyByteBuf.getBytes(bodyByteBuf.readerIndex(), array, 0, readableLen);
                offset = 0;
            }

            //反序列化
            MessageLite result = decodeBody(dataType, array, offset, readableLen);
//            ctx.fireChannelRead((Message.MessageBase)result);
            out.add(result);
            ReferenceCountUtil.release(bodyByteBuf);
        }
    }

    public MessageLite decodeBody(byte dataType, byte[] array, int offset, int length) throws Exception {
        if (dataType == 0x00) {
            return Message.MessageBase.getDefaultInstance().
                    getParserForType().parseFrom(array, offset, length);

        }
//        else if (dataType == 0x01) {
//            return OptionTickOuterClass.OptionTick.getDefaultInstance().
//                    getParserForType().parseFrom(array, offset, length);
//        }

        return null; // or throw exception
    }
}
package com.iscas.optocon.distribute.nettyserver.handler;

import com.google.protobuf.MessageLite;
import com.iscas.optocon.distribute.util.DataUtils;
import com.iscas.optocon.protobuf.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * //TODO
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2018/7/21 21:25
 * @since jdk1.8
 */
@ChannelHandler.Sharable
public class CustomProtobufEncoder extends MessageToByteEncoder<MessageLite> {

//    HangqingEncoder hangqingEncoder;
//
//    public CustomProtobufEncoder(HangqingEncoder hangqingEncoder)
//    {
//        this.hangqingEncoder = hangqingEncoder;
//    }

    @Override
    protected void encode(
            ChannelHandlerContext ctx, MessageLite msg, ByteBuf out) throws Exception {


        byte[] body = msg.toByteArray();
//        byte[] header = encodeHeader(msg, body.length);
        byte[] header = DataUtils.encodeHeader(msg, body.length);
        out.writeBytes(header);
        out.writeBytes(body);

        return;
    }


}

其他语言想与Netty服务通信,可以使用上面定义的协议头解析。

上一篇 Netty对象传输

猜你喜欢

转载自blog.csdn.net/u011943534/article/details/81174910