【问题标题】:Google ProtoBuf serialization / deserializationGoogle ProtoBuf 序列化/反序列化
【发布时间】:2013-06-13 07:49:24
【问题描述】:

我正在阅读Google Protocol Buffers。我想知道我可以Serialize C++ object 并将其通过网络发送到Java 服务器和Deserialize 那里的java 并自省这些字段。

我想将任何语言的对象发送到 Java 服务器。并在那里反序列化它。

假设以下是我的.proto 文件

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}

我对此运行protoc 并创建了一个C++ 对象。 基本上现在我想将序列化流发送到java 服务器。

在java端我可以deserialized流,这样我就可以找出流中有3字段及其各自的name, type, and value

【问题讨论】:

  • 编译相同的.proto文件并生成Java代码。然后在反序列化时使用它。
  • 哦,这意味着我将它用于客户端-服务器类型的模型,我还需要在服务器端有 .proto 文件。对!!!!
  • 他需要使用--java_out标志使protoc产生java代码IIRC
  • @Avinash:是的,所有使用 protobuf 的应用程序都必须知道 .proto 文件。看我的回答。

标签: java c++ protocol-buffers


【解决方案1】:

在java端我可以反序列化流,这样我就可以发现流中有3个字段及其各自的name、type和value

您需要提前了解架构。首先,protobuf 不传输名称;它用作标识符的只是每个字段的数字键(在您的示例中为1、2 和3)。其次,它没有明确指定类型; protobuf 中只有很少的线类型(varint、32 位、64 位、长度前缀、组);实际的 data 类型已映射到这些类型,但您无法在没有架构的情况下明确解码数据

  • varint 是“某种形式的整数”,但可以是有符号、无符号或“之字形”(允许对小幅度负数进行廉价编码),并且可以用于表示任何宽度的数据(64 位, 32 位等)
  • 32 位可以是整数,但可以是有符号或无符号 - 也可以是 32 位浮点数
  • 64 位可以是整数,但可以是有符号或无符号 - 也可以是 64 位浮点数
  • length-prefix 可以是一个 UTF-8 字符串、一个序列或原始字节(没有任何特殊含义)、一组“打包”的 repeated 一些原始类型(整数、浮点等)值,或可以是 protobuf 格式的结构化子消息
  • 组 - 万岁!这始终是明确的!这只能意味着一件事;但是一件事在很大程度上被谷歌弃用了:(

从根本上说:您需要架构。编码数据不包含你想要的。这样做是为了避免不必要的空间——如果协议假设编码器和解码器都知道消息的含义,那么需要发送的信息就会少很多。

但是,请注意, 包含的信息足以安全地往返消息,即使存在不期望的字段;如果您只需要对其进行重新编码以将其传递/返回,则无需知道名称或类型。

您可以做的是使用解析器 API 扫描数据以显示有三个字段,字段 1 是 varint,字段 2 是长度前缀,字段 3 是长度 -前缀。您可以对除此之外的数据进行有根据的猜测(例如,您可以查看 UTF-8 解码是否产生看起来大致类似于文本的内容,并验证 UTF-8 编码是否会返回给您原始字节;如果是,可能它是一个字符串)

【讨论】:

  • hmmm 谢谢 Marc,我想 Apache Avro 更有意义,因为我不想在服务器端使用模式,而 Apache Avro 说“当 Avro 数据存储在文件中时,它的模式会与它一起存储,以便任何程序稍后都可以处理文件。如果读取数据的程序需要不同的模式,这可以很容易地解决,因为两种模式都存在。"
  • @Avinash 一个脚注; protobuf .proto 模式可以打包并作为 protobuf 消息传输;但是,默认情况下不会发生这种情况,并且没有特定的 API 可以使这种透明化
  • 谢谢 Marc,但是即使我传输模式,我仍然需要在服务器端生成 java 代码,来解析序列化的消息对!!!!
  • 否 @Avinash 您可以使用 DynamicMessage 来检查正在发送的消息(尽管您仍然需要发送架构)。在 Avro 中可能会更容易,因为它在消息中包含架构
  • “你可以做的是使用解析器 API 扫描数据以显示有三个字段,字段 1 是 varint,字段 2 是长度前缀,字段 3 是长度前缀。” 有关如何执行此操作的任何示例/文档/讨论/指针?网上讨论这个的资源非常有限(也许这违背了 Protocol Buffer 的设计目标?),但我确实需要这个。是CodedInputStream吗?
【解决方案2】:

我可以序列化 C++ 对象并将其通过网络发送到 Java 服务器并在 Java 中反序列化并内省这些字段吗?

是的,这正是 protobuf 的目标。

序列化以任何支持的语言开发的应用程序中的数据,并反序列化以任何支持的语言开发的应用程序中的数据。序列化和反序列化语言可以相同,也可以不同。

请记住,协议缓冲区不是自我描述的,因此应用程序的双方都需要从.proto 文件生成序列化器/反序列化器。

【讨论】:

  • 默认情况下它们是非描述性的,但是将消息包装在提供自我文档的另一条消息中是微不足道的。 developers.google.com/protocol-buffers/docs/…
  • @g19fanatic:从来不需要自我描述的消息,但这很有趣。
【解决方案3】:

简而言之:是的,你可以。

您需要创建 .proto 文件来定义您想要共享的数据结构。通过使用Google Protocol Buffers 编译器,您可以为Java 和C++(以及您能想到的几乎任何其他语言)的结构生成接口和(反)序列化代码。

要通过网络传输数据,您可以使用 ZeroMQ,这是一个极其通用的通信框架,它还支持多种不同语言的 API,其中包括 Java 和 C++。

见this question for more details。

【讨论】:

    猜你喜欢
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 2020-04-22
    • 2021-10-15
    • 1970-01-01
    相关资源
    最近更新 更多