Google Protocol Buffer(protoc, protobuf, pb)學習筆記

分類:IT技術 時間:2017-07-08

以前玩 C,Json、XML 什麽的看多了,現在開始玩 C++,才發現我了解的世界太小了——原來 C++ 屆還有 Google Protocol Buffers 這麽好的東西。果然在 PC 上做開發真是好,不用考慮可執行程序的 size,可以放心放肆地用 C++。

Reference

Protocol Buffer Basics: C++
Google Protocol Buffers
Google Protocol Buffer 的使用和原理 - IBM
這是一份很有誠意的 Protocol Buffer 語法詳解

簡介

Protocol Buffers 又簡稱為 Protobuf、PB。是 Google 推出的一種數據交換格式。註意,這還是二進制的交換數據。

Protobuf 有自己的編譯器,在 linux 中叫做 protoc ,可以解釋 .proto 文件並且聲稱對應語言的源文件。目前 Google 提供了三種語言:Java, C++, python。後面我們就以 C++ 來說明,其他語言蕾絲。

總結一下:我們所說的 Protobuf,其實可以說是包含以下幾部分:

  • 一種數據交換格式,可以將 C++ 中定義的存儲類的內容 與 二進制序列串 相互轉換,主要用於數據傳輸或保存

  • 定義了一種源文件,擴展名為 .proto,使用這種源文件,可以定義存儲類的內容

  • Google 提供了一個編譯器 protoc,可以編譯 .proto 編譯成 .cc 文件,使之成為一個可以在 C++ 工程中直接使用的類。類的功能非常完善,後文輝具體說明。

.proto 的簡單語法

我們來定義一個可以覆蓋大多數使用情況的例子,定義一個高中的班級和班上學生的信息

// --------------------------------------
// File: School.HighSchool.proto
//
package School.HighSchool;     // 註意各種分號

message Person
{
    optional int32   id  = 0;
    optional int32   age = 0;
    optional string  first_name;
    optional string  last_name;
    optional bool    is_female;
};

message Class
{
    optional int32   grade_num;
    optional int32   class_num;
    optional Person  head_teacher;
    repeated Person  students;
};

文件的建議命名為 “包名.消息名.proto”。對於 C++ 而言,就是 “命名空間.數據類.proto”。

上面這段的語義,我直接用 C++ 的概念來說明吧:

  1. 定義包的分類(命名空間)是 School 類別下的 HighSchool 子類別。

  2. 定義一個 個人 數據類,包含學生的 ID、姓、名、性別等等信息。

  3. 定義一個 班級 數據類,包含年級號和班級號、班主任信息、所有學生的信息。

這裏有必要說明 optionalrepeated。前者表示這個數據類型是可選的,也就是說有可能不存在這樣的一個數據信息。後者表示這個數據類型是多個的,可以理解為一個,或者說一個 set、一個集合,總之就是多個同類數據,類似於 C++ 中的 vector。對應於 JSON 中的 array。Repeated 類型的數據有可能是空的(成員為 0)。

optional 相對應的是 required 類型,表示這個數據類型是必須的。但是,大部分資料都建議不要用這種類型。

生成 C++ 類

上面的源文件,可以使用以下命令進行編譯:

protoc -I=$SRC_DIR --cpp_out=$DST_DIR School.HighSchool.proto

編譯完成後,生成兩個文件:School.HighSchool.pb.ccSchool.HighSchool.pb.h

在類裏面,大體結構是這樣的:

namespace School {
namespace HighSchool {

class Person public ::google::protobuf::Message {
    ...
}    // end of class Student

class Class public ::google::protobuf::Message {
    ...
}    // end of class public

}}    // end of namespaces

對象函數方法

對象方法

一般而言生成的類,都有對應整個類的操作方法,常用的幾個方法如下:

operator= (...)
CopyFrom (...)
MergeFrom (...)
ByteSize () const
Swap (...)

而最重要的兩個方法則是:

bool SerializeToString (string *output) const;
bool ParseFromString (const string &data);

作用分別是序列化和反序列化,也就是

  1. 將 PB 的內容序列化(二進制化)到指定的 string 對象中。

  2. string 類型中解析出 PB 對象

get / set 方法

對於具體的數據成員,則給出具體的 get / set 方法。比如 Person 類的 id 成員,C++ 類會提供以下方法:

inline bool has_id() const;
inline void clear_id();
static const int kInt32IdNumber = 0;

inline ::google::protobuf::int32 id() const;
inline void set_id(::google::protobuf::int32 value);

所有的方法都按照字面意思就可以讀懂,非常好理解。

而對於 repeated 屬性的成員,比如 students,則比較復雜,使用了 STL:

inline int students_size() const;
inline void clear_students_size();

inline const ::School::HighSchool::Person &students(int index) const;
inline ::School::HighSchool::Person *mutable_students(int index);
inline ::School::HighSchool::Person *add_students();
inline const ::google::protobuf::RepeatedPtrField <::School::HighSchool::Person> &students() const;
inline ::google::protobuf::RepeatedPtrField <::School::HighSchool::Person> *mutable_students();

看起來比較復雜,其實還是很好理解的。請讀者結合 C++ 的叠代器理解就好了。

支持的基本數據類型

Protobuf 中常用的基本數據類型及必要的說明如下:

  • double

  • float

  • int32, int64:負數的編碼效率低於 sintXX 系列。當有負數,但是出現頻率不高時使用

  • uint32, uint64

  • sint32, sint64:當負數出現的頻率比較高時,比 int32 的效率高

  • fixed32, fixed64:註意,這不是 “定點數” 的意思,而是表示定長 4 字節的整形數據。如果數字長期大於 228 時,比 int32 效率更高

  • sfixed32, sfixed64

  • bool

  • string:ASCII / UTF-8 字符串

  • bytes:二進制序列


Tags: C++ 可以 Protocol Google 定義 proto

文章來源:


ads
ads

相關文章
ads

相關文章

ad