天天看點

資料傳輸 之 PB協定(protocol buffer)是什麼?怎麼寫?如何編譯?

資料傳輸 之 PB協定(protocol buffer)是什麼?怎麼寫?如何編譯?

文章目錄

    • 概念性的東西
      • 什麼是PB協定?
      • PB支援語言
      • 給出官網
    • 如何寫一個PB檔案
      • Protobuf消息定義
        • ①限定修飾符
        • ②資料類型速查
        • ④字段編碼值
        • ⑤預設值。
      • 幾個注意事項
        • import
        • 關于package
        • 關于enum
    • 編譯PB
      • 可編譯檔案
      • 放置位置
      • 開始編譯
      • 閱覽檔案

概念性的東西

什麼是PB協定?

ProtocolBuffer是用于序列化結構資料的靈活、高效、自動的方法,有如XML,不過它更小、更快、也更簡單。一旦定義了你自己的資料結構,然後就可以使用特殊生成的源代碼輕松的在各種資料流和使用的各種進階語言之間讀寫你的結構化資料。你甚至可以在不破壞根據“舊”格式編譯的已部署程式的情況下更新你的資料結構。

PB支援語言

Protocol buffers currently support generated code in Java, Python, Objective-C, and C++. With our new proto3 language version, you can also work with Go, Ruby, and C#, with more languages to come.

給出官網

官網在此,能力夠的朋友可以自行通路,英語能力一般的還是跟着我吧。

資料傳輸 之 PB協定(protocol buffer)是什麼?怎麼寫?如何編譯?

下載下傳的話,自行點選進去,在“How do I start?”闆塊下有下載下傳連結。

往下再拉,也有下載下傳連結。不過能不能打得開,就看運氣了,我開了四五次才加載出來。。。

如何寫一個PB檔案

Protobuf消息定義

你首先需要在一個 .proto 檔案中定義你需要做串行化的資料結構資訊。每個ProtocolBuffer資訊是一小段邏輯記錄,包含一系列的鍵值對。

消息由至少一個字段組合而成,類似于C語言中的結構。每個字段都有一定的格式。

字段格式:限定修飾符① | 資料類型② | 字段名稱③ | = | 字段編碼值④ | [字段預設值⑤]           

複制

這裡有個非常簡單的 .proto 檔案定義了個人資訊:

message Person {

required string name=1;
required int32 id=2;
optional string email=3;

enum PhoneType {
    MOBILE=0;
    HOME=1;
    WORK=2;
}

message PhoneNumber {
    required string number=1;
    optional PhoneType type=2 [default=HOME];
}

repeated PhoneNumber phone=4;
}           

複制

①限定修飾符

Required: 表示是一個必須字段,必須相對于發送方,在發送消息之前必須設定該字段的值,對于接收方,必須能夠識别該字段的意思。發送之前沒有設定required字段或者無法識别required字段都會引發編解碼異常,導緻消息被丢棄。

Optional:表示是一個可選字段,可選對于發送方,在發送消息時,可以有選擇性的設定或者不設定該字段的值。對于接收方,如果能夠識别可選字段就進行相應的處理,如果無法識别,則忽略該字段,消息中的其它字段正常處理。—因為optional字段的特性,很多接口在更新版本中都把後來添加的字段都統一的設定為optional字段,這樣老的版本無需更新程式也可以正常的與新的軟體進行通信,隻不過新的字段無法識别而已,因為并不是每個節點都需要新的功能,是以可以做到按需更新和平滑過渡。

Repeated:表示該字段可以包含0~N個元素。其特性和optional一樣,但是每一次可以包含多個值。可以看作是在傳遞一個數組的值。

②資料類型速查

Protobuf定義了一套基本資料類型。幾乎都可以映射到C++\Java等語言的基礎資料類型.

資料傳輸 之 PB協定(protocol buffer)是什麼?怎麼寫?如何編譯?
  1. N 表示打包的位元組并不是固定。而是根據資料的大小或者長度。
  2. 關于message,類似于C語言中的結構包含另外一個結構作為資料成員一樣。
  3. 關于 fixed32 和int32的差別。fixed32的打包效率比int32的效率高,但是使用的空間一般比int32多。是以一個屬于時間效率高,一個屬于空間效率高。根據項目的實際情況,一般選擇fixed32,如果遇到對傳輸資料量要求比較苛刻的環境,可以選擇int32.

④字段編碼值

編碼值的取值範圍為 1~2^32(4294967296)。

不信往上面翻翻看,看看是不是都是數值。

其中 1~15的編碼時間和空間效率都是最高的,編碼值越大,其編碼的時間和空間效率就越低(相對于1-15),當然一般情況下相鄰的2個值編碼效率的是相同的,除非2個值恰好實在4位元組,12位元組,20位元組等的臨界區。比如15和16.

1900~2000編碼值為Google protobuf 系統内部保留值,建議不要在自己的項目中使用。

protobuf 還建議把經常要傳遞的值把其字段編碼設定為1-15之間的值。

消息中的字段的編碼值無需連續,隻要是合法的,并且不能在同一個消息中有字段包含相同的編碼值。

⑤預設值。

當在傳遞資料時,對于required資料類型,如果使用者沒有設定值,則使用預設值傳遞到對端。當接受資料是,對于optional字段,如果沒有接收到optional字段,則設定為預設值。

幾個注意事項

import

protobuf 接口檔案可以像C語言的h檔案一樣,分離為多個,在需要的時候通過 import導入需要的檔案。

雖然可以在單個.proto檔案中定義多種消息類型(例如消息,枚舉和服務),但當在單個檔案中定義大量具有不同依賴性的消息時,也

可能導緻依賴性膨脹。建議每個.proto檔案包含盡可能少的消息類型。

關于package

避免名稱沖突,可以給每個檔案指定一個package名稱,對于C++解析為名稱空間。

記得在開頭加上這兩句:

syntax = "proto3";

package demo;           

複制

關于enum

枚舉的定義和C++相同,但是有一些限制。

  1. 枚舉值必須大于等于0的整數。
  2. 使用分号(;)分隔枚舉變量而不是C++語言中的逗号(,)

編譯PB

可編譯檔案

首先,你要有一個PB檔案可以拿去編譯,我知道你多半也沒有,沒事我這裡有。

syntax = "proto3";
 
package demo;
message Person {
    string name = 1;
    int32 id = 2;
    string email = 3;
 
    enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }
 
    message PhoneNumber {
        string number = 1;
        PhoneType type = 2;
    }
    repeated PhoneNumber phone = 4;
}           

複制

放置位置

愛放哪兒放哪兒,我放在了下載下傳檔案的同目錄下。

資料傳輸 之 PB協定(protocol buffer)是什麼?怎麼寫?如何編譯?

開始編譯

我下載下傳了好多款,不過主語言是C++,畢竟打開一次不容易。打不開下載下傳目錄的小夥伴可以私信我拿。

打開cmd, cd到該目錄,protoc.exe的指令行參數格式如下:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto           

複制

資料傳輸 之 PB協定(protocol buffer)是什麼?怎麼寫?如何編譯?

編譯之後就會出現新的檔案了。

閱覽檔案

打開之後太長了,自己去看。我這裡提幾點。

(1)proto中的package在C++中是namespace;

(2)proto中的message在C++中是class,類裡面有各個成員的set/get;基類是google::protobuf::Message。

(3)代碼中可以看見C++11中的移動構造和移動指派函數。           

複制

至于API啊,實際操作的時候再說吧。