【问题标题】:Protobuf serialization length differs when using different values for field使用不同的字段值时,Protobuf 序列化长度不同
【发布时间】:2017-06-28 15:08:31
【问题描述】:

我的 Protobuf 消息由 3 个双精度组成

syntax = "proto3";

message TestMessage{
  double input = 1;
  double output = 2;
  double info = 3;
}

当我将这些值设置为

test.set_input(2.3456);
test.set_output(5.4321);
test.set_info(5.0);

序列化的消息看起来像

00000000  09 16 fb cb ee c9 c3 02  40 11 0a 68 22 6c 78 ba  |........@..h"lx.|
00000010  15 40 19                                          |.@.|
00000013

当使用 test.serializeToArray 时,使用相同的 protobuf 消息的 go 程序无法成功反序列化。尝试从 c++ 程序中读取它时,我得到了一个 0 作为信息,因此该消息似乎已损坏。

当使用test.serializeToOstream时,我收到了这条消息,go和c++程序都可以成功反序列化。

00000000  09 16 fb cb ee c9 c3 02  40 11 0a 68 22 6c 78 ba  |........@..h"lx.|
00000010  15 40 19 00 00 00 00 00  00 14 40               |.@........@|
0000001b

将值设置为时

test.set_input(2.3456);
test.set_output(5.4321);
test.set_info(5.5678);

test.serializeToArraytest.serializeToOstream 产生的序列化消息看起来像

00000000  09 16 fb cb ee c9 c3 02  40 11 0a 68 22 6c 78 ba  |........@..h"lx.|
00000010  15 40 19 da ac fa 5c 6d  45 16 40                 |.@....\mE.@|
0000001b

并且可以被我的 go 和 cpp 程序成功读取。

我在这里缺少什么?为什么serializeToArray 在第一种情况下不起作用?

编辑: 事实证明,serializeToString 也可以正常工作。

这里是我用来比较的代码:

file_a.open(FILEPATH_A);
file_b.open(FILEPATH_B);

test.set_input(2.3456);
test.set_output(5.4321);
test.set_info(5.0);

//serializeToArray
int size = test.ByteSize();
char *buffer = (char*) malloc(size);
test.SerializeToArray(buffer, size);
file_a << buffer;

//serializeToString
std::string buf;
test.SerializeToString(&buf);
file_b << buf;

file_a.close();
file_b.close();

为什么 serializeToArray 不能按预期工作?

EDIT2:

当使用file_b &lt;&lt; buf.data() 而不是file_b &lt;&lt; buf.data() 时,数据也会损坏,但为什么呢?

【问题讨论】:

  • 你在 Go 中说你得到相同的长度,但是当你得到不同的长度时你用什么?
  • 是的,第一个版本是错误的 IMO。它应该是 27 个字节。您可以在这里输入十六进制 protogen.marcgravell.com/decode 来验证并查看 27 字节版本的相同数字
  • 当我在 go 中执行与 cpp 中相同的操作时,两个序列化消息的长度相同,而 cpp 序列化的长度不同
  • size 是什么出来的,顺便说一句?
  • size 是 27,如果我没记错的话应该是正确的

标签: c++ serialization go protocol-buffers


【解决方案1】:

我认为您所犯的错误是将二进制视为字符数据并使用字符数据 API。许多 API 在第一个零字节 (0) 处停止,但这在 protobuf 二进制文件中是完全有效的值。

您需要确保您基本上不使用任何此类 API - 完全坚持使用二进制安全 API。

由于您指出size 是 27,所以这一切都合适。

基本上,5.0 的二进制表示包括 0 个字节,但您很容易看到其他值的时间相同的问题。

【讨论】:

  • 所以问题是file_b &lt;&lt; buffer,因为我传递了一个 char 数组并且 ostream 在第一个 nil 字节之后结束了写入,因为它期望一个以 null 结尾的字符串?
  • @jonadev95 是的,就是这样
猜你喜欢
  • 1970-01-01
  • 2018-12-01
  • 2021-12-20
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 2020-04-01
  • 1970-01-01
相关资源
最近更新 更多