目录
- 简介
- 官方API解读(C++)
- 定义一个Protocol Format
- 编译Protocol Buffers
- The Protocol Buffer API
- 解析和序列化
- 官方示例注释
- 总结
你知道的越多,你知道的越少。
简介
什么是protobuf
?
protocol buffers
是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等
在网络通信和通用数据交换等应用场景中经常使用的技术是 JSON
或 XML
Protocol Buffers
是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML
,但是比 XML
更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序
其具有以下特点:
- 语言无关、平台无关。即
ProtoBuf
支持 Java
、C++
、Python
等多种语言,支持多个平台 - 高效。即比
XML
更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单 - 扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序
官网:protobuf官网
官方示例:官方示例下载
GitHub源码:protobuf-GitHub
官方API解读(C++)
大致步骤:
- 定义一个
.proto
文件 - 使用
protocol buffer
编译器 - 使用
c++ API
读写这个文件
定义一个Protocol Format
定义一个Protocol
模板
message Example1 {optional string stringVal = 1;optional bytes bytesVal = 2;message EmbeddedMessage {int32 int32Val = 1;string stringVal = 2;}optional EmbeddedMessage embeddedExample1 = 3;repeated int32 repeatedInt32Val = 4;repeated string repeatedStringVal = 5;
}
message
关键字后跟上消息名称
message xxx {// do something
}
之后我们在其中定义了 message
具有的字段,形式为:
message xxx {// 字段规则:required -> 字段只能也必须出现 1 次// 字段规则:optional -> 字段可出现 0 次或1次// 字段规则:repeated -> 字段可出现任意多次(包括 0)// 类型:int32、int64、sint32、sint64、string、32-bit ....// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)字段规则 类型 名称 = 字段编号;
}
关于保留字required
、optional
、repeated
可见
required
:必须为该字段提供一个值,否则该消息将被视为“未初始化”optional
:该字段可能被设置,也可能没有设置repeated
:该字段可以重复任何次数(包括零)
更多介绍可见官网
编译Protocol Buffers
我们在 .proto
文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输
当需要把这些数据进行存储或传输时,就需要将这些结构数据进行序列化、反序列化以及读写。那么如何实现呢?不用担心, ProtoBuf
将会为我们提供相应的接口代码。如何提供?答案就是通过 protoc
这个编译器
编译器下载地址:protoc编译器下载
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
他最后会生成两个文件
addressbook.pb.h
:声明生成的类的头文件addressbook.pb.cc
:其中包含您的类的实现
The Protocol Buffer API
对于一个message
,protoc都会生成一个struct(class)
,而struct
中的属性字段,都会自动的生成一些访问器
inline bool has_name() const;inline void clear_name();inline const ::std::string& name() const;inline void set_name(const ::std::string& value);inline void set_name(const char* value);inline ::std::string* mutable_name();
类中的方法本身是隐式的内联函数inline
而对于一些可重复的字段repeated
,会生成以下字段
inline int phones_size() const;inline void clear_phones();inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const;inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones();inline const ::tutorial::Person_PhoneNumber& phones(int index) const;inline ::tutorial::Person_PhoneNumber* mutable_phones(int index);inline ::tutorial::Person_PhoneNumber* add_phones();
更详细可见C&#43;&#43; generated code reference
还有一些标准接口
每个消息类还包含许多其他方法&#xff0c;让你检查或操作整个消息&#xff0c;包括:
bool IsInitialized() const;
&#xff1a; 检查是否设置了所有必需的字段。string DebugString() const;
&#xff1a;返回人类可读的消息表示形式&#xff0c;对调试特别有用。void CopyFrom(const Person& from);
&#xff1a;使用给定消息的值覆盖消息。void Clear();
&#xff1a;将所有元素清除回空状态
解析和序列化
最后&#xff0c;每个协议缓冲区类都有使用协议缓冲区二进制格式编写和读取所选类型的消息的方法。这些包括&#xff1a;
bool SerializeToString(string* output) const;
&#xff1a;对消息进行序列化并将字节存储在给定字符串中。注意&#xff0c;字节是二进制的&#xff0c;不是文本;我们只将string类用作方便的容器。bool ParseFromString(const string& data);
&#xff1a;解析来自给定字符串的消息bool SerializeToOstream(ostream* output) const;
&#xff1a;将消息写入给定的c&#43;&#43; ostream。bool ParseFromIstream(istream* input);
&#xff1a;从给定的c&#43;&#43; istream中获取消息。
官方示例注释
#include
#include
#include
#include "addressbook.pb.h"
using namespace std;
void PromptForAddress(tutorial::Person* person) {
}int main(int argc, char* argv[]) {GOOGLE_PROTOBUF_VERIFY_VERSION;tutorial::AddressBook address_book;{fstream input(argv[1], ios::in | ios::binary);if (!input) {cout << argv[1] << ": File not found. Creating a new file." << endl;} else if (!address_book.ParseFromIstream(&input)) {cerr << "Failed to parse address book." << endl;return -1;}}PromptForAddress(address_book.add_people());{fstream output(argv[1], ios::out | ios::trunc | ios::binary);if (!address_book.SerializeToOstream(&output)) {cerr << "Failed to write address book." << endl;return -1;}}google::protobuf::ShutdownProtobufLibrary();return 0;
}
总结
XML
、JSON
、ProtoBuf
都具有数据结构化和数据序列化的能力XML
、JSON
更注重数据结构化&#xff0c;关注人类可读性和语义表达能力。ProtoBuf
更注重数据序列化&#xff0c;关注效率、空间、速度&#xff0c;人类可读性差&#xff0c;语义表达能力不足&#xff08;为保证极致的效率&#xff0c;会舍弃一部分元信息&#xff09;ProtoBuf
的应用场景更为明确&#xff0c;XML
、JSON
的应用场景更为丰富
只能说&#xff0c;各有所长&#xff0c;各有所短吧。
参考&#xff1a;
- 深入 ProtoBuf - 简介
- protobuf官网