05-技术

本页描述了一些常用的处理protocol buffers的设计模式。还可以将设计和使用问题发送到protocol buffers讨论组

0.1. 流式传输多条消息

如果要将多条消息写入单个文件或流,则需要跟踪一条消息的结束位置和下一条消息的开始位置。

protocol buffers传输格式不是自定界限的,因此protocol buffers解析器无法确定消息自身的结束位置。

解决此问题的最简单方法是:在写入消息之前写入每条消息的大小。当重新读取消息时,读取大小,然后将字节读入单独的缓冲区,然后从该缓冲区解析。

如果想避免将字节复制到一个单独的缓冲区,请查看CodedInputStream类(在C++Java中),该类可以将读取限制为一定的字节数。

0.2. 大数据集

protocol buffers不是为处理大型消息而设计的。作为一般经验法则,如果正在处理大于每兆字节的消息,则可能需要考虑替代策略。

也就是说,protocol buffers非常适合处理大型数据集中的单个消息。通常,大型数据集实际上只是一些小部分的集合,其中每个小部分可能是结构化的数据。尽管protocol buffers无法同时处理整个集合,但使用protocol buffers对每个部分进行编码可以极大地简化问题:现在只需要处理一组字节组成的字符串而不是一整个结构。

protocol buffers不包括对大型数据集的任何内置支持,因为不同的情况需要不同的解决方案。有时是一个简单的记录列表,而有时可能想要更像数据库的东西。每个解决方案都应该作为一个单独的库开发,以便只有需要它的人才需要支付成本。

0.3. 自描述消息

protocol buffers不包含其自身类型的描述。因此,只给出没有定义其类型的原始消息而没有相应的定义它类型的.proto文件,很难提取任何有用的数据。

但是,请注意.proto文件的内容本身可以使用protocol buffers表示。源代码包中的文件src/google/protobuf/descriptor.proto定义了所涉及的消息类型。protoc可以使用--descriptor_set_out选项输出FileDescriptorSet(表示一组.proto文件)。有了这个,可以定义一个自描述协议消息,如下所示:

syntax = "proto3";

import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";

message SelfDescribingMessage {
  // Set of FileDescriptorProtos which describe the type and its dependencies.
  google.protobuf.FileDescriptorSet descriptor_set = 1;

  // The message and its type, encoded as an Any message.
  google.protobuf.Any message = 2;
}

通过使用DynamicMessage(可在C++Java中使用)这样的类,可以编写可以操作SelfDescribingMessages的工具。

总而言之,这个功能未包含在protocol buffers库中的原因是因为从未在Google内部使用它。

此技术需要使用描述符支持动态消息。在使用自描述消息之前,请检查平台是否支持此功能。

上次修改: 14 April 2020