1. 程式人生 > >Protobuf 序列化協議詳解

Protobuf 序列化協議詳解

Protocol Buffers是Google開發一種資料描述語言,能夠將結構化資料序列化,可用於資料儲存、通訊協議等方面。據Google官方文件介紹,現在Google內部已經有48,162個訊息型別定義在12,183個proto檔案中。本文會從快速入門、語言規範、編碼協議、效能評估等幾個方面對Prototol Buffers進行介紹。

替代文字
替代文字

不瞭解Protocol Buffers的同學可以把它理解為更快、更簡單、更小的JSON或者XML,區別在於Protocol Buffers是二進位制格式,而JSON和XML是文字格式。

替代文字

相對於XML,Protocol Buffers的具有如下幾個優點:
  • 簡潔
  • 體積小:訊息大小隻需要XML的1/10 ~ 1/3
  • 速度快:解析速度比XML快20 ~ 100倍
  • 使用Protocol Buffers的編譯器,可以生成更容易在程式設計中使用的資料訪問程式碼
  • 更好的相容性,Protocol Buffers設計的一個原則就是要能夠很好的支援向下或向上相容。
替代文字

看一個簡單的對比例子,表達一個使用者的三個基本的屬性,如果使用XML訊息體大小為82 bytes。
替代文字

如果使用JSON訊息體大小為56 bytes。
替代文字

使用Protocol Buffers咋則只需要 31 bytes,看到這些二進位制資料大家可以暫時忽略,後面會具體分析這些二進位制資料是如何編碼的。
替代文字

接下來先看一個簡單的入門示例,在該例子中我們從準備環境開始,編寫proto檔案,到最後使用Protocol Buffers編譯器生成程式碼,再到具體的使用。
替代文字

https://github.com/google/protobuf下載編譯安裝protoc,並下載Protobuf SDK。
替代文字

開始編寫proto檔案,使用message關鍵字定義訊息型別,訊息中每個欄位需要指定欄位型別和欄位序號。同一個message中欄位
替代文字

使用protoc命令生成程式碼,使用--cpp_out、--java_out、--python_out命令選項可以生成C++、Java、Python程式碼,在最新版本Protocol Buffers v3中還加入了ruby語言的支援。
替代文字

生成程式碼的程式碼可以直接加入到自己的程式碼工程中使用,以C++語言為例:
替代文字

這是一段Java語言的使用示例:
替代文字

接下來會詳細說明如何定義proto檔案:
替代文字

在訊息定義中,我們需要確定三個問題:
  • 確定訊息命名,給訊息取一個有意義的名字。
  • 指定欄位的型別
  • 定義欄位的編號,在Protocol Buffers中,欄位的編號非常重要,欄位名僅僅是作為參考和生成程式碼用。需要注意的是欄位的編號區間範圍,其中19000 ~ 19999被Protocol Buffers作為保留欄位。

    替代文字

    欄位約束,required指定該欄位必須賦值,禁止為空(在v3中該約束被移除);optional指定欄位為可選欄位,可以為空,對於optional欄位還可以使用[default]指定預設值,如果沒有指定,則會使用欄位型別的預設值;使用repeated指定欄位為集合。
    替代文字

    在一個proto檔案中可以同時定義多個message型別,生成程式碼時根據生成程式碼的目標語言不同,處理的方式不太一樣,如Java會針對每個message型別生成一個.java檔案。還可以使用C++風格的註釋。
    替代文字

    在Protocol Buffers中提供了很多的標量型別,供我們在定義欄位型別時使用。
    替代文字

    可以指定欄位的型別為其他message型別,如圖中的示例程式碼所示:
    替代文字

    還可以使用import關鍵字匯入其他proto檔案,這有利於你進行自己的proto檔案的規劃和整理。
    替代文字

    在proto檔案中訊息的型別還可以巢狀,如你定義的message型別僅作為另外一個Message的欄位型別。
    替代文字

    為了便於擴充套件,在proto檔案中可以使用extensions關鍵字預留一部分欄位編號出來,以便於後期給第三方擴充套件時使用。
    替代文字

    oneof關鍵字指定一組欄位中,至少要有一個欄位必須賦值。如在使用者登入系統中,使用郵箱和使用者名稱都可以登入該系統,所以通常會要求至少提供使用者名稱或者郵箱。
    替代文字