Netty protobuf的编解码使用
来源:互联网 发布:淘宝宝贝仓库在哪 编辑:程序博客网 时间:2024/05/21 15:02
Netty为protobuf提供了两个编码器(ProtobufEncoder,ProtobufVarint32LengthFieldPrepender),两个解码器(ProtobufVarint32FrameDecoder,ProtobufDecoder)。
只需要在childHandler()中设置好以上编解码器就可以使用protobuf传输数据。
服务器端:
Netty已经把所有的protobuf的细节给封装过了,包括半包粘包的处理。看一下Netty是如何发送和接受protobuf数据的(基于Netty4.0.33)。
ProtobufVarint32LengthFieldPrepender:
解码的过程无非就是先读出length来,根据length读取出所有的数据来,交给protobuf就能还原消息出来。ProtobufVarint32FrameDecoder:
ProtobufDecoder:
只需要在childHandler()中设置好以上编解码器就可以使用protobuf传输数据。
服务器端:
.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(new ProtobufVarint32FrameDecoder()) .addLast(new ProtobufDecoder( ProtoObject.Req.getDefaultInstance())) .addLast(new ProtobufVarint32LengthFieldPrepender()) .addLast(new ProtobufEncoder()) .addLast(new ServerHandler()); }})客户端:
.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(new ProtobufVarint32FrameDecoder()) .addLast(new ProtobufDecoder( ProtoObject.Resp.getDefaultInstance())) .addLast(new ProtobufVarint32LengthFieldPrepender()) .addLast(new ProtobufEncoder()) .addLast(new ClientHandler()); }})
Netty已经把所有的protobuf的细节给封装过了,包括半包粘包的处理。看一下Netty是如何发送和接受protobuf数据的(基于Netty4.0.33)。
public class ProtobufEncoder extends MessageToMessageEncoder<MessageLiteOrBuilder> { @Override protected void encode( ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out) throws Exception { if (msg instanceof MessageLite) { out.add(wrappedBuffer(((MessageLite) msg).toByteArray())); return; } if (msg instanceof MessageLite.Builder) { out.add(wrappedBuffer(((MessageLite.Builder) msg).build().toByteArray())); } }}encode方法很简单,实际上它会调用protobuf的api,把消息编码成protobuf格式的字节数组。
ProtobufVarint32LengthFieldPrepender:
public class ProtobufVarint32LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> { @Override protected void encode( ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { int bodyLen = msg.readableBytes(); int headerLen = CodedOutputStream.computeRawVarint32Size(bodyLen); out.ensureWritable(headerLen + bodyLen); CodedOutputStream headerOut = CodedOutputStream.newInstance(new ByteBufOutputStream(out), headerLen); headerOut.writeRawVarint32(bodyLen); headerOut.flush(); out.writeBytes(msg, msg.readerIndex(), bodyLen); }}它会在原来的数据的前面,追加一个使用Base 128 Varints编码过的length。例如:
* BEFORE DECODE (300 bytes) AFTER DECODE (302 bytes)* +---------------+ +--------+---------------+* | Protobuf Data |-------------->| Length | Protobuf Data |* | (300 bytes) | | 0xAC02 | (300 bytes) |* +---------------+ +--------+---------------+
解码的过程无非就是先读出length来,根据length读取出所有的数据来,交给protobuf就能还原消息出来。ProtobufVarint32FrameDecoder:
public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder { // TODO maxFrameLength + safe skip + fail-fast option // (just like LengthFieldBasedFrameDecoder) @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { in.markReaderIndex(); final byte[] buf = new byte[5]; for (int i = 0; i < buf.length; i ++) { if (!in.isReadable()) { in.resetReaderIndex(); return; } buf[i] = in.readByte(); if (buf[i] >= 0) { int length = CodedInputStream.newInstance(buf, 0, i + 1).readRawVarint32(); if (length < 0) { throw new CorruptedFrameException("negative length: " + length); } if (in.readableBytes() < length) { in.resetReaderIndex(); return; } else { out.add(in.readBytes(length)); return; } } } // Couldn't find the byte whose MSB is off. throw new CorruptedFrameException("length wider than 32-bit"); }}
ProtobufDecoder:
public class ProtobufDecoder extends MessageToMessageDecoder<ByteBuf> { private static final boolean HAS_PARSER; static { boolean hasParser = false; try { // MessageLite.getParsetForType() is not available until protobuf 2.5.0. MessageLite.class.getDeclaredMethod("getParserForType"); hasParser = true; } catch (Throwable t) { // Ignore } HAS_PARSER = hasParser; } private final MessageLite prototype; private final ExtensionRegistryLite extensionRegistry; /** * Creates a new instance. */ public ProtobufDecoder(MessageLite prototype) { this(prototype, null); } public ProtobufDecoder(MessageLite prototype, ExtensionRegistry extensionRegistry) { this(prototype, (ExtensionRegistryLite) extensionRegistry); } public ProtobufDecoder(MessageLite prototype, ExtensionRegistryLite extensionRegistry) { if (prototype == null) { throw new NullPointerException("prototype"); } this.prototype = prototype.getDefaultInstanceForType(); this.extensionRegistry = extensionRegistry; } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { final byte[] array; final int offset; final int length = msg.readableBytes(); if (msg.hasArray()) { array = msg.array(); offset = msg.arrayOffset() + msg.readerIndex(); } else { array = new byte[length]; msg.getBytes(msg.readerIndex(), array, 0, length); offset = 0; } if (extensionRegistry == null) { if (HAS_PARSER) { out.add(prototype.getParserForType().parseFrom(array, offset, length)); } else { out.add(prototype.newBuilderForType().mergeFrom(array, offset, length).build()); } } else { if (HAS_PARSER) { out.add(prototype.getParserForType().parseFrom(array, offset, length, extensionRegistry)); } else { out.add(prototype.newBuilderForType().mergeFrom(array, offset, length, extensionRegistry).build()); } } }}
阅读全文
0 0
- Netty protobuf的编解码使用
- Netty使用Protobuf进行编解码
- Netty系列-使用Google Protobuf编解码
- Netty使用google protobuf进行编解码
- netty编解码之使用protobuf
- [netty]-消息编解码之google的Protobuf编解码
- Netty之Google Protobuf编解码
- Netty学习(七)-Netty编解码技术以及ProtoBuf和Thrift的介绍
- Netty实战(二)Netty服务器,采用Protobuf编解码
- 《netty权威指南》8Google Protobuf编解码
- Netty 权威指南之Google protobuf 编解码
- Netty编解码框架:Java序列化、Protobuf、 Marshalling
- Netty的入门-编解码技术
- Netty 之 Netty使用Google的ProtoBuf
- Netty编解码技术
- netty 对 protobuf 协议的解码与包装探究(2)
- 十一、Google Protobuf 编解码
- netty开发tcp数据传输编解码框架使用
- C语言可变参数--va_list、va_start、va_arg、va_end
- Screen, Viewport 和 Rect 浅析
- Boolan STL与泛型编程 第四周笔记
- Centos7 安装go语言开发环境
- C++写二叉树
- Netty protobuf的编解码使用
- 2017.6.15
- PNP: non-blocking IO
- 树形dp——洛谷 P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…
- codeforces—— 579A —— Raising Bacteria
- latex 加减号堆积,放在一起
- 好好用心学好JAVA语言
- Linux 正则表达式详解
- 2017.06.15--spark中cache和persist的区别