目录
- [1. Protobuf 概述](#1. Protobuf 概述)
-
- [1.1 定义](#1.1 定义)
- 1.2Protobuf的优势
- [2. Protobuf 语法](#2. Protobuf 语法)
- 3、序列号和反序列化
-
- [3.1 .pb.h 头文件](#3.1 .pb.h 头文件)
- [3.2 序列化](#3.2 序列化)
- [3.3 反序列化](#3.3 反序列化)
- 4、测试用例
1. Protobuf 概述
1.1 定义
protobuf也叫protocol buffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#、c++、go 和 python 等,每一种实现都包含了相应语言的编译器以及库文件。
由于它是一种二进制的格式,比使用 xml 、json进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。
1.2Protobuf的优势
使用Protobuf 进行数据通信的优势可以简短概括为以下几点:
- 效率:二进制格式,序列化和反序列化速度快。
- 紧凑性:数据体积小,节省存储和传输带宽。
- 类型安全:编译时类型检查,减少运行时错误。
- 向后兼容:支持平滑升级,易于维护。
- 跨语言:支持多种编程语言。
- 扩展性:支持消息扩展,适应不断变化的数据需求。
- 字段编号:唯一标识,便于版本控制和更新。
2. Protobuf 语法
Protobuf文件后缀指定为 .proto,在文件的第一行需要指定Protobuf的版本号,有两个版本Protobuf 2 和 Protobuf 3,此处我们使用的是版本3。
cpp
// Person.proto
syntax = "proto3";
// 在该文件中对要序列化的结构体进行描述
message Person
{
int32 id = 1;
bytes name = 2;
bytes sex = 3;
int32 age = 4;
}
message后面的名字就是生成的类的名字,自己指定一个合适的名字即可
等号后面的编号要从1开始,每个成员都有一个唯一的编号,不能重复,一般连续编号即可。
.proto文件编辑好之后就可以使用protoc工具将其转换为C++文件了:
cpp
protoc -I path .proto文件 --cpp_out=输出路径(存储生成的c++文件)
如果想要在当前目录下,也就是和.proto文件在一级目录下生成pb.cc和pb.h文件,执行:
cpp
$ protoc ./Person.proto --cpp_out=.
# 或者使用 -I 参数
$ protoc -I ./ Person.proto --cpp_out=.
3、序列号和反序列化
3.1 .pb.h 头文件
通过protoc 命令对.proto文件的转换,得到的头文件中有一个类,这个类的名字和 .proto文件中message关键字后边指定的名字相同,.proto文件中message消息体的成员就是生成的类的私有成员。
那么如何访问生成的类的私有成员呢? 可以调用生成的类提供的公共成员函数,这些函数有如下规律:
- 清空(初始化) 私有成员的值: clear_变量名()
- 获取类私有成员的值: 变量名()
- 给私有成员进行值的设置: set_变量名(参数)
- 得到类私有成员的地址, 通过这块地址读/写当前私有成员变量的值: mutable_变量名()
- 如果这个变量是数组类型:
(1)数组中元素的个数: 变量名_size()
(2)添加一块内存, 存储新的元素数据: add_变量名() 、add_变量名(参数)
3.2 序列化
序列化 是指将数据结构或对象转换为可以在储存或传输中使用的二进制格式的过程。在计算机科学中,序列化通常用于将内存中的对象持久化存储到磁盘上,或者在分布式系统中进行数据传输和通信。
Protobuf 中为我们提供了相关的用于数据序列化的 API,如下所示:
cpp
// 头文件目录: google\protobuf\message_lite.h
// --- 将序列化的数据 数据保存到内存中
// 将类对象中的数据序列化为字符串, c++ 风格的字符串, 参数是一个传出参数
bool SerializeToString(std::string* output) const;
// 将类对象中的数据序列化为字符串, c 风格的字符串, 参数 data 是一个传出参数
bool SerializeToArray(void* data, int size) const;
// ------ 写磁盘文件, 只需要调用这个函数, 数据自动被写入到磁盘文件中
// -- 需要提供流对象/文件描述符关联一个磁盘文件
// 将数据序列化写入到磁盘文件中, c++ 风格
// ostream 子类 ofstream -> 写文件
bool SerializeToOstream(std::ostream* output) const;
// 将数据序列化写入到磁盘文件中, c 风格
bool SerializeToFileDescriptor(int file_descriptor) const;
3.3 反序列化
反序列化是指将序列化后的二进制数据重新转换为原始的数据结构或对象的过程。通过反序列化,我们可以将之前序列化的数据重新还原为其原始的形式,以便进行数据的读取、操作和处理。
Protobuf 中为我们提供了相关的用于数据序列化的 API,如下所示:
cpp
// 头文件目录: google\protobuf\message_lite.h
bool ParseFromString(const std::string& data) ;
bool ParseFromArray(const void* data, int size);
// istream -> 子类 ifstream -> 读操作
// wo ri
// w->写 o: ofstream , r->读 i: ifstream
bool ParseFromIstream(std::istream* input);
bool ParseFromFileDescriptor(int file_descriptor);
4、测试用例
开发环境:Ubuntu20.04、VScode
本人仓库地址:基于VScode和C++ 实现Protobuf数据格式的通信