Protocol buffers 最大序列化Protobuf消息大小

Protocol buffers 最大序列化Protobuf消息大小,protocol-buffers,Protocol Buffers,有没有办法在序列化某个protobuf消息后获取其最大大小 我指的是不包含“重复”元素的消息 请注意,我指的不是包含特定内容的protobuf消息的大小,而是它可能达到的最大大小(在最坏的情况下)。据我所知,Google自己的protobuf中没有计算最大大小的功能 尽可能计算最大大小,并在生成的文件中将其导出为#define 根据。通常,由于可能存在未知字段,任何Protobuf消息都可以是任意长度,因此手动计算小消息也非常简单 如果您正在接收消息,则不能对长度进行任何假设 如果您正在发送一条

有没有办法在序列化某个protobuf消息后获取其最大大小

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


请注意,我指的不是包含特定内容的protobuf消息的大小,而是它可能达到的最大大小(在最坏的情况下)。

据我所知,Google自己的protobuf中没有计算最大大小的功能

尽可能计算最大大小,并在生成的文件中将其导出为
#define


根据。

通常,由于可能存在未知字段,任何Protobuf消息都可以是任意长度,因此手动计算小消息也非常简单

如果您正在接收消息,则不能对长度进行任何假设

如果您正在发送一条您自己构建的消息,那么您可以假设它只包含您知道的字段——但是,在这种情况下,您也可以轻松地计算出确切的消息大小

因此,询问最大尺寸通常是没有用的

也就是说,您可以编写代码,使用
描述符
接口在
字段描述符
上迭代消息类型(
MyMessageType::Descriptor()

见:

类似的接口存在于Java、Python和其他语言中

以下是要实施的规则:

每个字段由一个标记和一些数据组成

对于标签:

  • 字段号1-15有一个1字节的标记
  • 字段编号16及以上具有2字节标记
有关数据:

  • bool
    始终为一个字节
  • int32
    int64
    uint64
    sint64
    的最大数据长度为10字节(是的,
    int32
    如果为负数,则可能为10字节)
  • sint32
    uint32
    的最大数据长度为5字节
  • fixed32
    sfixed32
    float
    始终正好是4个字节
  • fixed64
    sfixed64
    double
    始终正好是8个字节
  • 枚举类型字段的最大长度取决于最大枚举值:
    • 0-127:1字节
    • 128-16384:2字节
    • 。。。它是每字节7位,但希望您的枚举没有那么大
    • 还要注意,负值将被编码为10字节,但希望没有任何字节
  • 消息类型字段的最大长度是消息类型的最大长度加上长度前缀的字节数。长度前缀同样是每7位整数数据一个字节
  • 组(您不应该使用它;它们是在protobuf公开发布之前就被弃用的陈旧功能)的最大大小等于内容的最大大小加上第二个字段标记(见上文)
如果您的邮件包含以下任何内容,则其最大长度是无限的:

  • 字符串
    字节
    类型的任何字段。(除非您知道它们的最大长度,在这种情况下,它是最大长度加上长度前缀,就像子消息一样。)
  • 任何重复的字段。(除非您知道其最大长度,在这种情况下,列表中的每个元素都有一个最大长度,就好像它是一个独立的字段,包括标记。这里没有总长度前缀。除非您使用的是
    [packed=true]
    ,在这种情况下,您必须查找详细信息。)
  • 扩展

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

太棒了!如果有什么东西可以在运行时做到这一点,那就太好了,但我想编译时就可以了。。。下周我将尝试Python脚本,看看是否能完成任务。谢谢如果为负,您确定
int32
最多需要10个字节吗?AFAIK使用varint编码的任何int32最多可以使用5个字节进行编码。@tigrou是的,我确定,因为我写了代码。:)负int32必须填充到10字节,因为int32预期与int64s前向兼容,因此如果需要,您可以在将来将现有的int32字段更改为int64。