最大序列化Protobuf消息大小

时间:2015-06-18 12:44:26

标签: protocol-buffers

有没有办法在序列化后获得某个protobuf消息的最大大小?

我指的是不包含“重复”元素的消息。

请注意,我指的是具有特定内容的protobuf消息的大小,但指的是它可以到达的最大可能大小(在最坏的情况)。

3 个答案:

答案 0 :(得分:14)

通常,任何protobuf消息都可以是任何长度,因为可能存在未知字段。如果您收到消息,则无法对长度做出任何假设。如果您发送您自己构建的消息,那么您可以假设它只包含您知道的字段 - 但是,在这种情况下,您还可以轻松计算确切的消息大小。因此,通常无法询问最大尺寸是多少。

话虽如此,您可以编写使用Descriptor接口的代码来迭代FieldDescriptor以获取消息类型(MyMessageType::descriptor())。

请参阅:https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.descriptor

类似的接口存在于Java,Python和其他可能的接口中。

以下是要实施的规则:

每个字段由一个标记后跟一些数据组成。

对于标签:

  • 字段编号1-15具有1字节标记。
  • 字段编号16及以上有2字节标记。

对于数据:

  • bool总是一个字节。
  • int32int64uint64sint64的最大数据长度为10个字节(是的,int32如果是,则可以是10个字节不幸的是,这是负面的。
  • sint32uint32的最大数据长度为5个字节。
  • fixed32sfixed32float总是正好是4个字节。
  • fixet64sfixed64double总是正好是8个字节。
  • 枚举字段的最大长度取决于最大枚举值:
    • 0-127:1字节
    • 128-16384:2个字节
    • ...每个字节有7位,但希望你的枚举不是那么大!
    • 另请注意,负值将被编码为10个字节,但希望没有任何。
  • 消息类型字段的最大长度是消息类型的最大长度加上长度前缀的字节。长度前缀同样是每7位整数数据一个字节。
  • 组(您不应该使用它们;它们是在protobuf公开发布之前弃用的旧旧功能)的最大大小等于内容的最大大小加上第二个字​​段标记(参见上文)。

如果您的邮件包含以下任何内容,则其最大长度无限制:

  • stringbytes类型的任何字段。 (除非你知道它们的最大长度,在这种情况下,它是最大长度加上长度前缀,就像子消息一样。)
  • 任何重复的字段。 (除非你知道它的最大长度,在这种情况下,列表的每个元素都有一个最大长度,好像它是一个独立的字段,包括标记。这里没有总长度前缀。除非你使用{{1} },在这种情况下,您将不得不查找详细信息。)
  • 扩展。

答案 1 :(得分:4)

据我所知,没有任何功能可以计算谷歌自己的protobuf的最大尺寸。

Nanopb generator会尽可能计算最大大小,并将其作为#define导出到生成的文件中。

根据protobuf encoding documentation手动计算小邮件也很简单。

答案 2 :(得分:3)

在实施protobuffer 3消息大小计算时,我发现Kenton所说的大部分内容都是正确的。我确实遇到了一个疏忽:标签是从字段编号创建的,左移3位,然后按线类型(在wire_format_lite.h中找到)进行按位或运算。然后将该结果编码为var int。因此对于刚好超过16的标签,标签将是2个字节,但如果字段数更大(> ~1000),则标签将大于3个字节。对于protobuffer 3用户来说这可能不是问题,因为字段数量大是对protobuf的误用。