修改原始protobuf流

modify raw protobuf stream

本文关键字:protobuf 原始 修改      更新时间:2023-10-16

假设我使用以下原型文件编译了一个应用程序(Receiver(:

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

我有另一个应用程序(Transmitter(,它最初有相同的原型文件,但在更新后添加了一个新字段,如:

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

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

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

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

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

提前感谢

我不认为有官方的方法可以做到这一点(https://developers.google.com/protocol-buffers/docs/encoding#structure)。

基本上你应该这样做:

  • 从第一位开始解码
  • 解码,直到达到id的字段号
  • 识别表示id的位,并将其替换为新的(编码的!(id

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

在proto2语法中,protobuf C++库用于保留未知字段,以便在重新编码消息时保留这些字段。不幸的是,这个特性(和其他许多特性一样(已经在proto3语法中删除了。

一种变通方法是这样做:

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

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


嗯,实际上阅读了上面链接的问题报告,似乎你可以在protobuf 3.5及更新版本中打开未知字段保存。

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