有没有针对不同语言的稳定的序列化方法?

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) 能够反序列化来自其他语言的字符串,但反之则不行。

问题是:

  1. 为什么 C++ protobuf 会产生不同的字符串?
  2. 我们的用例可以使用哪些库?

详情:

// 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

what is serialization

我认为 protobuf 与术语序列化混淆了。 protobuf 所做的是一种特殊的编码。这除了

我怀疑不设置 b 会导致问题。这意味着 b 的值未初始化。 java 对象自动初始化为零,c++ 对象不自动初始化,这意味着内容可能只是随机值。 b

可能会发生

事实证明,我打印 hexstring 的代码中有错误。 details

简答: Protobuf 是一种稳定的序列化方法,可用于描述的用例。

Protobuf 不稳定,因为内存中的同一个对象可以用不同的方式序列化。主要是因为当一个对象有多个字段时,字段可以按任意顺序序列化。

在此处查看文档:https://developers.google.com/protocol-buffers/docs/encoding#implications .