有没有针对不同语言的稳定的序列化方法?
Is there any stable serialization method for different languages?
在我的项目中我们有一个 API,许多客户可能会向这个 API 发送交易。交易应该被签署。客户端可以用任何语言(C++、C#、python、go,等等)编写,具有任何 CPU 体系结构和字节顺序。
现在的问题是将我们的交易模型序列化为字节,以便能够签名然后发送。
我们的团队为此选择了 protobuf v3.3.0(proto syntax = proto3)。
我们想使用信封图案,看起来像:
message SignedTransaction {
message Transaction {/* any data that should be signed */}
Transaction transaction = 1;
Signature signature = 2;
}
为了签名,我们只需序列化内部对象交易:
Transaction tx = <...>;
std::string bytes = tx.SerializeAsString();
// and then sign bytes
protobuf 现在的问题是,对于不同的语言,它似乎不是确定性的。今天我们写了一个简单的 proto 文件,其中包含少量整数和字符串,填充相同的数据,针对不同的语言对其进行序列化并观察结果。
我们尝试了 Javascript、C++、Java、Swift,结果发现除 C++ 之外的所有内容都产生相同的输出字符串:
Java脚本,Java,Swift制作:08B90A10BA0A1A106C6F6C206B656B20636865627572656B
C++ 产生:8FFFFFFB9A10FFFFFFBAA1A106C6F6C206B656B20636865627572656B
C++ parseFromString(str)
能够反序列化来自其他语言的字符串,但反之则不行。
问题是:
- 为什么 C++ protobuf 会产生不同的字符串?
- 我们的用例可以使用哪些库?
详情:
// test.proto:
syntax = "proto3";
package api;
message Msg {
uint32 a = 1;
int32 b = 2;
string c = 3;
bytes d = 4;
}
// test.cpp:
api::Msg msg;
msg.set_a(1337);
msg.set_b(1338);
msg.set_c("lol kek cheburek");
std::string str = msg.SerializeAsString();
// str = 8FFFFFFB9A10FFFFFFBAA1A106C6F6C206B656B20636865627572656B
我认为 protobuf 与术语序列化混淆了。 protobuf 所做的是一种特殊的编码。这除了
我怀疑不设置 b
会导致问题。这意味着 b 的值未初始化。 java 对象自动初始化为零,c++ 对象不自动初始化,这意味着内容可能只是随机值。 b
可能会发生
事实证明,我打印 hexstring 的代码中有错误。 details
简答:
Protobuf 是一种稳定的序列化方法,可用于描述的用例。
Protobuf 不稳定,因为内存中的同一个对象可以用不同的方式序列化。主要是因为当一个对象有多个字段时,字段可以按任意顺序序列化。
在此处查看文档:https://developers.google.com/protocol-buffers/docs/encoding#implications .
在我的项目中我们有一个 API,许多客户可能会向这个 API 发送交易。交易应该被签署。客户端可以用任何语言(C++、C#、python、go,等等)编写,具有任何 CPU 体系结构和字节顺序。
现在的问题是将我们的交易模型序列化为字节,以便能够签名然后发送。
我们的团队为此选择了 protobuf v3.3.0(proto syntax = proto3)。
我们想使用信封图案,看起来像:
message SignedTransaction {
message Transaction {/* any data that should be signed */}
Transaction transaction = 1;
Signature signature = 2;
}
为了签名,我们只需序列化内部对象交易:
Transaction tx = <...>;
std::string bytes = tx.SerializeAsString();
// and then sign bytes
protobuf 现在的问题是,对于不同的语言,它似乎不是确定性的。今天我们写了一个简单的 proto 文件,其中包含少量整数和字符串,填充相同的数据,针对不同的语言对其进行序列化并观察结果。
我们尝试了 Javascript、C++、Java、Swift,结果发现除 C++ 之外的所有内容都产生相同的输出字符串:
Java脚本,Java,Swift制作:08B90A10BA0A1A106C6F6C206B656B20636865627572656B
C++ 产生:8FFFFFFB9A10FFFFFFBAA1A106C6F6C206B656B20636865627572656B
C++ parseFromString(str)
能够反序列化来自其他语言的字符串,但反之则不行。
问题是:
- 为什么 C++ protobuf 会产生不同的字符串?
- 我们的用例可以使用哪些库?
详情:
// test.proto:
syntax = "proto3";
package api;
message Msg {
uint32 a = 1;
int32 b = 2;
string c = 3;
bytes d = 4;
}
// test.cpp:
api::Msg msg;
msg.set_a(1337);
msg.set_b(1338);
msg.set_c("lol kek cheburek");
std::string str = msg.SerializeAsString();
// str = 8FFFFFFB9A10FFFFFFBAA1A106C6F6C206B656B20636865627572656B
我认为 protobuf 与术语序列化混淆了。 protobuf 所做的是一种特殊的编码。这除了
我怀疑不设置 b
会导致问题。这意味着 b 的值未初始化。 java 对象自动初始化为零,c++ 对象不自动初始化,这意味着内容可能只是随机值。 b
事实证明,我打印 hexstring 的代码中有错误。 details
简答: Protobuf 是一种稳定的序列化方法,可用于描述的用例。
Protobuf 不稳定,因为内存中的同一个对象可以用不同的方式序列化。主要是因为当一个对象有多个字段时,字段可以按任意顺序序列化。
在此处查看文档:https://developers.google.com/protocol-buffers/docs/encoding#implications .