在外部消息中包含预编码的协议缓冲区消息 有没有一种方法在C++中创建一个协议缓冲消息,包含一个预先编码的内部消息,不进行解析,然后重新序列化内部消息?< /P> 为了澄清,请考虑下面的消息定义: message Inner { required int i = 1; // ... more fields ... } message Outer { repeated Inner inners = 1; // ... more fields ... }

在外部消息中包含预编码的协议缓冲区消息 有没有一种方法在C++中创建一个协议缓冲消息,包含一个预先编码的内部消息,不进行解析,然后重新序列化内部消息?< /P> 为了澄清,请考虑下面的消息定义: message Inner { required int i = 1; // ... more fields ... } message Outer { repeated Inner inners = 1; // ... more fields ... },c++,protocol-buffers,C++,Protocol Buffers,假设您有一个10字节数组的集合,每个数组都包含一个内部数组的编码版本。您希望创建一个包含10个内部的外部。您不想手工编码,因为Outer有其他字段,并且它本身可能包含在其他消息中。有没有办法让协议缓冲区直接复制预编码的内部数据?没有干净的方法,但有一些不太好的方法。一种是定义第二条消息,如下所示: message RawOuter { repeated bytes inners = 1; // ... same fields as Outer ... } RawOuter与Ou

假设您有一个10字节数组的集合,每个数组都包含一个内部数组的编码版本。您希望创建一个包含10个内部的外部。您不想手工编码,因为Outer有其他字段,并且它本身可能包含在其他消息中。有没有办法让协议缓冲区直接复制预编码的内部数据?

没有干净的方法,但有一些不太好的方法。一种是定义第二条消息,如下所示:

message RawOuter {
    repeated bytes inners = 1;
    // ... same fields as Outer ...
}
RawOuter
Outer
相同,只是
inners
重复字段已从type
Inner
更改为type
bytes
。如果使用
internal
的编码实例填充
inners
,然后序列化
RawOuter
,则得到的结果与使用解析的verison构建
Outer
完全相同。也就是说,嵌套消息的wire格式与包含该嵌套消息序列化的
字节
字段的wire格式相同。这是protobuf编码的一个有趣的可利用的怪癖

不过,这种黑客行为也有一些问题。特别是,如果您试图构建一个嵌入到其他一些proto中的
Outer
实例,它将无法正常工作,因为您可能不希望维护每个包含消息的两个副本,一个使用
Outer
,另一个使用
RawOuter

另一个甚至更黑客的选择是将编码的消息注入
外部
实例的
未知字段集

Outer outer;
for (auto& inner: inners) {
  outer.mutable_unknown_fields()
      ->AddLengthDelimited(1, inner);
}
UnknownFieldSet
用于存储解析时看到的字段,这些字段与
.proto
文件中定义的任何已知字段号都不匹配。其思想是,这允许您编写一个代理服务器,只接收消息并将其转发到另一个服务器,而无需在每次向协议添加新字段时重新编译代理。在这里,我们通过在其中插入一个值来滥用它,该值实际上对应于一个已知字段,但是实现不会注意到,因此它会很好地写出这些字段

这种方法的主要问题是,如果其他人同时检查您的
外部
实例,他们会觉得
内部
列表是空的,因为这些值实际上隐藏在其他地方。这是一个相当丑陋的黑客,可能会回来困扰你以后。只有当您测量了性能差异并发现差异很大时,我才会推荐它

还要注意,序列化代码总是最后写入未知字段,而已知字段是按字段编号顺序写入的。解析器应该接受任何顺序,但有时您会发现有人将未解析的数据用作哈希映射键或其他东西,如果字段被重新排序,则会完全中断

顺便说一下,您可以通过将字符串交换到位而不是复制来提高这两种方法的性能,即

raw_outer->add_inners()->swap(inner);

outer->mutable_unknown_fields()->AddLengthDelimited(1)->swap(inner);