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