【问题标题】:modify raw protobuf stream修改原始 protobuf 流
【发布时间】:2018-08-05 01:49:06
【问题描述】:

假设我已经使用以下 proto 文件编译了一个应用程序(接收器):

syntax = "proto3";  
message Control {   
    bytes version = 1;  
    uint32 id = 2; 
    bytes color = 3;
}

我有另一个应用程序(传输器),它最初具有相同的 proto 文件,但在更新后添加了一个新字段,如:

syntax = "proto3";  
message Control {   
    bytes name = 1;  
    uint32 id = 2; 
    bytes color = 3;
    uint32 color_id = 4;
}

我已经看到,如果 Receiver 应用程序尝试解析 proto,更改一些数据,然后将其序列化回来,来自 Transmitter 应用程序的添加字段将被删除。

我需要一种方法来更改直接访问原始字节的 id 字段,而无需解析/序列化 proto。有可能吗?

这是必需的,因为我在控制消息中有一些“标题”字段,我知道这些字段永远不会更改,但由于应用程序更新,可以在相同的传输器应用程序原型中添加/更改其他字段。

我见过:https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.coded_stream 但我无法修改现有的字节流,并且 ReadString 无法理解字符串长度。

提前致谢

【问题讨论】:

  • 如果您使用的是 protobuf 2 或 3.5+ developers.google.com/protocol-buffers/docs/proto3#unknowns,应该可以正常工作
  • 请问您确切地指出您使用的是哪个版本?从 v3.5.0 开始,C++ 应该默认为 proto3 保留未知字段...(这是 proto2,IIRC 中的旧行为)

标签: c++ protocol-buffers


【解决方案1】:

我认为没有官方的方法可以做到这一点。您可以按照 protobuf (https://developers.google.com/protocol-buffers/docs/encoding#structure) 的编码指南手动执行此操作。

基本上你应该这样做:

  • 从第一位开始解码
  • 解码,直到达到 id 的字段编号
  • 识别代表 id 的位并用您的新(编码!)id 替换它们

这很糟糕有几个原因。最重要的是,您的代码必须了解有关消息结构和内容的详细信息(您的 id 的字段编号和数据类型),而这正是您在使用协议缓冲区时要避免的(您总是需要 .proto 文件中的一些信息) )。

【讨论】:

  • 这个想法是存在的,但很糟糕。原因是如果他必须在几个月后再次更改消息怎么办。然后他需要更换定制的解码器。这样做的唯一原因是性能,在这种情况下,您应该了解 protobuf 的内部结构。
【解决方案2】:

在 proto2 语法中,protobuf C++ 库用于保留未知字段,以便在您重新编码消息时,它们将保留。不幸的是,这个特性(和许多其他特性一样)have been removed 在 proto3 语法中。

一种解决方法可能是这样做:

  1. 仅在Receiver 消息中设置新的id 值并对其进行编码。
  2. 将此数据附加到原始二进制数据之后。

这依赖于 protobuf 特性,即附加消息替换 protobuf 消息中字段的原始值。


嗯,其实看了上面链接的问题报告,好像是you can turn on unknown field preservation in protobuf version 3.5 and newer。

【讨论】:

    【解决方案3】:

    只需反序列化整个消息并将其映射到新消息。这是最干净的方式。您没有大量数据,可能没有实时要求。创建一个映射器,不要过度思考问题。

    【讨论】:

      猜你喜欢
      • 2020-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-10
      • 2012-07-25
      • 2013-03-27
      • 2012-12-02
      • 2017-09-11
      相关资源
      最近更新 更多