序列化及其作用

序列化是将数据结构或对象转换为可存储或传输的格式的过程。序列化可以将数据结构或对象转换为一系列字节,以便它们可以存储在磁盘上或通过网络传输。在序列化过程中,数据被编码为一个特定的格式,这个格式可以在需要时被解码回原始数据结构或对象。

序列化可以用于许多不同的目的,包括:

  1. 数据持久化: 序列化可以将数据存储在磁盘上,以便在程序关闭后再次使用。这种用法可以用于保存应用程序的状态或用户数据等。

  2. 数据传输: 序列化可以将数据编码为字节,以便通过网络传输。这种用法可以用于将数据发送给其他应用程序或其他计算机。

  3. 进程间通信: 序列化可以将数据结构或对象传递给其他进程或线程。这种用法可以用于不同的应用程序之间进行通信,或者在单个应用程序的不同部分之间进行通信。

  4. 对象复制: 序列化可以用于创建一个对象的副本。这种用法可以用于创建测试数据或备份数据等。

总之,序列化是一种非常有用的技术,它可以帮助程序在不同的环境中传输和存储数据,提高程序的可扩展性和互操作性。

序列化数据结构协议Protocol Buffers(protobuf)

什么是 Protocol Buffers?

Protocol Buffers是一种轻量级的数据交换格式,它使用二进制编码,并且可在不同平台和语言间进行相互传递、解析和序列化。

与XML 和 JSON 不同,PB 具有更高的编码密度,解析速度更快,因此是处理大型数据集或需要高效通信的场景中常用的技术之一。

Protocol Buffers有3个核心部分:

  1. 定义文件:proto文件定义了数据结构和对象之间的关系。
  2. 编译器:Proto编译器可以将proto文件编译成所需语言的代码文件和库文件,例如Java、C++、Python、Go等。
  3. API库:开发人员可以使用生成的代码库来创建和解析protobuf消息。

Protocol Buffers 的优点

在应用程序设计中,Protocol Buffers具有以下几个显著的优势:

  1. 最小化数据大小:Protocol Buffers采用二进制编码格式并压缩数据大小,从而实现更短的消息长度,占用更小的磁盘空间和网络带宽。

  2. 简单:Proto文件是易读的,方便理解你正在处理的数据。同时,Proto消息还可以很容易地转换为其他编程语言,从而加快了集成的进程。

  3. 快速的编解码速度:由于 Protocol Buffers 是以二进制形式表示的,所以通常会比文本格式要快。由于原生类型在 Protocol Buffers 中已经被优化过,所以它们可以更快地序列化和反序列化。

  4. 向后兼容性: 添加新字段在 Protocol Buffers 中非常方便。如果你有重要字段的更改需求,可以通过保留标记、删除标记和默认值等方式,做到向前和向后的兼容性。

  5. IDL+Codegen: 通过 Protocol Buffers 的 IDL(Interface Definition Language)定义,我们可以根据语言特性生成代码,省去手写 Java POJO 或 Python 代码等工作量。

总体上,ProtoBuf 的主要优点是高效、可扩展和可互操作。如果数据传输的时候需要考虑带宽、解析速度、安全等问题,那么 Protocol Buffers 则是一个很好的选择。

Proto 2语法

定义一个消息

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}

指派字段编号

在protobuf中,每个字段都需要有唯一的标识符来进行序列化和反序列化。这个数字就是所谓的“字段编号”或“标签号”,它通常被定义在.proto文件中的message内部。

对于一个message中的每个字段,其标签号必须是唯一的且大于零。此外,还有一些保留的标签号,如0用于表示标记为不使用,19000到19999用于预留非公开使用等。

例如,下面是一个message定义,

message Person {
  int32 id = 1;
  string name = 2;
  repeated string phone_numbers = 3;
}

在上述示例中,id字段具有标签号为1,name字段具有标签号为2,phone_numbers字段具有标签号为3。这些标签号将作为不同消息的二进制编码中的标识符。

因此,标签号是protobuf中消息定义的重要组成部分,它们用于识别将在二进制格式中编码的消息内容,并且在更改现有message时需要格外小心地处理它们。

消息定义中的每个字段都有一个唯一的编号。这些数字用于标识消息二进制格式的字段,一旦使用了消息类型,就不应该更改它们。范围1到15的字段编码需要一个字节,包括字段编号和字段类型(您可以在 Protocol Buffer Encoding 中找到更多关于这方面的信息)。范围为16到2047的字段号占用两个字节。因此,应该为频繁出现的消息元素保留字段编号1到15。请记住为将来可能添加的频繁出现的元素留出一些空间。

字段规则

proto2 中的字段规则主要有以下几种:

  1. required(需要特别小心,如果后期要弃用的话会导致老版本的不兼容问题)
    表示该字段必须在消息中出现且不为空,否则将无法进行序列化或者反序列化操作。
  2. optional:
    表示该字段是可选的,不一定在消息中出现。若某个可选字段在消息中未出现,在反序列化后该字段的值为空。
  3. repeated:
    表示该字段可以重复出现多次,比如数组或列表等。

以上规则仅适用于 proto2 版本,已在 proto3 版本中被弃用。

保留字段

在 Proto2 中,Reserved 关键字用于指定保留字段,以避免未来的修改时添加该字段。保留字段用于指定特定的字段号,以确保它们不会在协议的演化期间被重新定义和使用。保留字段有助于解决兼容性问题并改进协议增量变更的支持。

语法格式如下:

message Foo {
  required int32 bar = 1;
  reserved 2, 15, 27 to 29;
  optional string baz = 3;
}

保留字段可以通过单个数字、连续的数字范围或逗号分隔的数字列表来指定。此外,在一个保留组之前声明的消息字段不能被在该组内保留。如果需要在保留组之前保留某些字段,则应该将多个保留组作为协议的一部分进行声明。

通常在删除一个字段的时候为了向前兼容,都会将删除的字段先声明为Reserved

Protocol Buffer C++ API

https://protobuf.dev/getting-started/cpptutorial/