技巧

相关技术

本页将介绍一些处理 Protocol Buffers 的常用设计模式。你可以将设计和使用相关的问题发送到 Protocol Buffers 讨论组.

多消息(Message)流

如果你想将多个消息写入一个文件或流(stream)中,那么是由你来记录一个消息的终点以及另一个消息的起点的。Protocol Buffer数据传输格式不是自我限定的(self-delimiting),所以protocol buffer解析器无法自己决定一个消息结束于何处。解决这个问题的最简单的方法就是:在写入每一个消息之前,先写入消息的大小。当你读取消息的时候,先读取消息大小,然后将指定的字节数读入一个独立的缓冲区中,然后再解析缓冲区里的东西。如果你不想将数据拷贝到一个独立的缓冲区中,请查看CodedInputStream类(C++和Java都可用)的使用方法——你可以用它来限制只读取指定字节的数据。

大数据集

Protocol Buffers不是设计来处理大消息的。根据一般经验,如果你要处理的单条消息大于1M,那就是采取其他策略的时候了。

也就是说,Protocol Buffers非常适合于处理一个大数据集内有多个单独的消息。通常,大数据集只是许多小块数据的集合,每一小块都是一块结构化的数据。即使是这样,Protocol Buffers也不能马上处理整个数据集,使用Protocol Buffers来编码每一块数据可以极大地简化你的问题:现在你所需要的只是处理一组字符串,而不是一组结构体了。

Protocol Buffers没有内置任何对大数据集的支持,因为不同的情况需要不同的解决方案。

有时,一个简单的记录列表就解决问题了,而在某些情况下,你可能更想要的是类似于数据库的东西。每个解决方案都应该作为一个独立的库来开发,所以只有需要它的人才需要付出代价。

自描述信息

Protocol Buffers 并不包含其自身类型的描述。所以如果没有给出定义类型的 .proto 文件,而只有原始信息(raw message)是很难提取任何有用数据的。

译者注:
自描述信息对于反射实现至关重要

然而,值得注意的是 .proto 文件的内容本身实际上也可以使用 protocol buffers 来表达。源码中的 src/google/protobuf/descriptor.proto 定义了所需的相关类型。protoc 命令可以使用 –descriptor_set_out 选项来输出 FileDescriptorSet(此类就表示一组 .proto 文件)。通过这种方式,你可以定义一个自描述的协议消息,如下所示:

message SelfDescribingMessage {
  // Set of .proto files which define the type.
  required FileDescriptorSet proto_files = 1;

  // Name of the message type.  Must be defined by one of the files in
  // proto_files.
  required string type_name = 2;

  // The message data.
  required bytes message_data = 3;
}

通过 DynamicMessage 类(C++ 和 Java 中可用),你可以编写操作上述 SelfDescribingMessages 的工具。

简单来讲的话,这个功能之所以未包含在 Protocol Buffer 库中,是因为我们从未在 Google 内部使用过它。

此技术需要对 proto2 语法的支持(因为这是 descriptor.proto 使用的语法)以及对使用描述符的动态信息的支持。在使用自描述消息之前,请检查你需要的平台是否支持这些功能。