Protocol Buffers 開發者指南

歡迎來到 protocol buffers 的開發者指南。protocol buffers 是一個語言中立,平臺中立針對通信協議,數據存儲和其餘領域中對結構化數據進行序列化的擴展方法。html

本文檔主要針對的是 Java,C++ 或 Python 的開發人員但願在開發的應用程序中使用 Protocol Buffers。這個有關 Protocol Buffers 摘要性的介紹將會告訴你如何開始使用 Protocol Buffers。若是你但願更加深刻的瞭解有關 Protocol Buffers 的內容,你能夠進入 tutorials 或者 protocol buffer encoding 頁面來詳細瞭解。java

有關 API 的參考文檔,請參考頁面:reference documentation 這裏提供了全部這 3 種語言的參考,同時也針對 .proto language 和 style 提供相關的指南。ios

什麼是 Protocol Buffers?

Protocol buffers 是對結構化數據序列化的一個靈活,高效,自動化工具 —— 你能夠將 Protocol buffers 想象成 XML,可是體積更小,更快也更加簡單。git

你能夠本身定義你的結構化數據,而後你可使用特定的代碼生成工具來很是容易對你的結構化數據進行讀取和寫入。這些數據的讀取和寫入能夠是一系列的數據流和使用不一樣的計算機程序語言。你甚至能夠在不對已經部署的程序進行破壞的狀況下更新你的數據結構。github

Protocol Buffers 是如何進行工做的

你須要制定你但願如何將你的數據進行序列化。你是經過 proto 文件來定義你的消息結構化數據的。golang

每一 protocol buffer message 是一個小的信息記錄邏輯,這個消息中包含有一系列的名字,變量對照序列。下面是一些基本的.proto 文件,這些文件中定義了一個消息,這個消息包含有一個 person 信息:服務器

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 ;
}

經過上面你能夠看到這個消息的格式很是簡單—— 每個消息類型都有一個或者多個惟一進行編號的字段,每個字段包含有一個名字和變量類型。數據結構

變量能夠爲數字(整形或者浮點型)(numbers),布爾類型(booleans),字符串(strings),原生二進制(raw bytes)甚至其餘的 protocol buffer 消息類型,可以容許你分級的結構化你的數據。eclipse

你能夠將字段指定爲可選字段(optional fields),必須字段(required fields)和重複字段(repeated fields)。你能夠從下面的 Protocol Buffer Language Guide 頁面中找到更多有關 .proto 的定義。ide

一旦你成功定義了你的消息,你能夠針對你使用的語言使用你定義的 .proto 來運行 protocol buffer 編譯器(protocol buffer compiler)來生成數據訪問類。

針對每個字段,在數據訪問類中提供了簡單的訪問方法(例如 name() 和 set_name())和序列化到原生 2 進制數據和從原生 2 進制數據反序列化的方法。

針對上面的定義,若是你如今使用的是  C++ 語言的話,當你把消息定義進行編譯後,你將會獲得一個稱爲 Person 的類。 你可使用這個類在你的應用程序中進行填充數據,對數據進行序列化和從序列化的數據中(protocol buffer 消息)從新得到 Person 數據。

而後你能夠寫一些相似 Person person; 的代碼。

Person person;
person.set_name( "John Doe" );
person.set_id( 1234 );
person.set_email( "jdoe@example.com" );
fstream output( "myfile" , ios::out | ios::binary);
person.SerializeToOstream(&output);

隨後,你能夠對消息進行讀取:

fstream input( "myfile" , ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout <<  "Name: "  << person.name() << endl;
cout <<  "E-mail: "  << person.email() << endl;

你能夠向你的消息中添加新的字段而不會損壞老的消息。這是由於在老的消息處理中,針對新的字段是徹底忽略掉的。所以,若是你在你的通信協議中使用 protocol buffers 爲數據結構的話,你能夠對你的協議和消息進行擴展而不須要擔憂老的代碼沒有辦法編譯經過,或者損壞老的代碼。

你能夠訪問 API Reference section 頁面中的內容來了解完整 protocol buffer 代碼的生成和使用。

你也能夠在 Protocol Buffer Encoding 頁面中瞭解更多protocol buffer 消息是如何進行編碼的。

爲何不使用 XML

針對 XML 來講 Protocol Buffers 具備更多的優點來對序列化結構數據。

  • 更加簡單
  • 小於 XML  3 到 10 倍
  • 快於 XML 20 到 100 倍
  • 鬆耦合
  • 使用程序工具來建立數據訪問類,使數訪問類更加簡單

假設,你須要講 person 這個數據進行定義,在 XML 你須要使用:

<person>
   <name>John Doe</name>
   <email>jdoe @example .com</email>
</person>

來進行定義。

在 Protocol Buffers 中針對上面的消息文本化(text format)後顯示爲:

# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
   name:  "John Doe"
   email:  "jdoe@example.com"
}

當上面的消息被編碼爲 Protocol Buffer 二進制格式(binary format)上面的文字可能小於 28 bytes,而且可能須要 100-200 納秒(nanoseconds)來進行處理。

咱們將上面轉換爲能夠人爲讀取的目的主要是爲進行調試和編輯。

若是你使用 XML 的話,上面的信息至少須要 69 bytes (你須要刪除全部的空格),同時你須要 5,000-10,000 納秒(nanoseconds)來進行處理。

同時,對 protocol buffer 進行操做也是很是容易的:

cout <<  "Name: "  << person.name() << endl;
cout <<  "E-mail: "  << person.email() << endl;

若是使用的是 XML 的話,你須要進行下面的操做:

cout <<  "Name: "
      << person.getElementsByTagName( "name" )->item( 0 )->innerText()
      << endl;
cout <<  "E-mail: "
      << person.getElementsByTagName( "email" )->item( 0 )->innerText()
      << endl;

可是,protocol buffers 並非任什麼時候候都會比 XML 好。例如,針對基於文本的標記語言(例如,XML),protocol buffers 就不是一個很好的選項,由於你不能使用 protocol buffer 更好的在文檔中進行交換。更主要的是 HTML 是人類能夠閱讀和編輯的。protocol buffer 也不是不能夠人爲的讀取,可是針對原生的 protocol buffer 格式是沒有辦法人爲進行讀取和編輯的。

XML 與  HTML 同樣,在某種程度上是一種自我描述數據。protocol buffer 只針對你在 .proto 文件中描述的內容進行表達。

看起來像一個解決方案,我應該如何開始呢?

Download the package – 這包中含有針對 Java, Python, 和 C++ protocol buffer 編譯器源代碼,和你須要進行 I/O 和測試的類。但願對你的編譯器進行編譯和構建,請參考代碼中的 README 文件。

一旦你完成了全部的設置,請參考 tutorial 頁面中的內容來選擇你須要的語言——這個可以幫助你使用 protocol buffer 建立一個簡單的應用程序。

介紹 proto3

在咱們最新的 version 3 發行版 中推出了新的語言版本 —— Protocol Buffers language version 3(另稱 proto3),在這個版本中針對咱們已經存在的語言版本(proto2)使用了一些新的特性。

Proto3 簡化了 protocol buffer 語言,使其更加容易使用而且可以支持更多的語言:咱們當前發行的 proto3 可以讓你建立 Java, C++, Python, Java Lite, Ruby, JavaScript, Objective-C, and C#。

另外你也能夠經過使用 Go protoc 插件來用 proto3 建立 Go 代碼,這個插件你能夠到 golang/protobuf Github 中下載到。更多的語言還在逐步進行支持中。

請注意,這 2 個版本的 API 並非徹底兼容的。爲了照顧還在使用老版本的用戶,咱們將會在新的 protocol buffers 發行中同時支持老的版本。

你能夠在下面的發行日志(release notes)查看 2 個版本的主要不一樣。有關 proto3 的句法,請參考 Proto3 Language Guide 中的內容,針對 proto3 的完整文檔尚未編寫完成,將會隨後推出。

看起來 proto2 和 proto3 可能會產生一些混淆,這是由於原始的開源  protocol buffers 其實是 Google 內部語言的第二個版本,同時咱們的開源版本也是從 v2.0.0 開始的。簡單來講就是 proto 最開始的版本是 Google 內部使用的,在 proto 第二個版本的時候,Google 決定進行開源了,因此開源的 proto 是從 proto2 開始的。

一個簡短的歷史

Protocol buffers 最開始是在 Google 內部進行開發的,用於處理在索引服務器上請求/響應(request/response)的協議。

在 Protocol buffers 以前,針對請求和響應,使用的是 marshalling/unmarshalling,這個可以支持一系列的協議。可是結果看起來倒是很是的難看,例如:

if  (version ==  3 ) {
   ...
else  if  (version >  4 ) {
   if  (version ==  5 ) {
     ...
   }
   ...
}

明確格式化的的協議也使新版本的協議更加難以推出,這是由於開發者必須可以瞭解老協議在服務器之間是如何進行處理的,同時也須要了解新的協議。只有對新老協議都有所瞭解後才能逐步使用新的協議替換老的協議。

Protocol buffers 被用來設計解決上面的不少問題:

  • 新的字段比較可以容易的進行定義,中級服務器不須要對數據進行檢查,直接對數據進行處理,同時也能夠直接傳輸數據而不須要了解數據是如何進行定義的。
  • 格式使用自描述,可以更加容易支持更多的語言(C++,Java 等)。

可是,用戶仍是須要手動書寫他們本身的處理diam。

做爲系統的進化來講,它得到了許多其餘的特性和用途:

  • 自動生成序列化和反序列化代碼而避免手動書寫這些代碼。
  • 除了開始使用短時間RPC(遠程過程調用)請求,人們開始使用 protocol buffers 做爲高效的自描述結構化數據格式(主要針對數據短時間存在,例如在 Bigtable)。
  • 服務器RPC接口開始被聲明爲協議文件的一部分,協議編譯器生成根類,用戶能夠經過服務器接口的實現和重載它們。

Protocol buffers 在 Google 中成爲針對數據的通用語言—— 隨着時間的流逝,在 Google 內部已經有超過 348,952 .proto 文件被定義。這些被用在 RPC 系統和存儲系統中存儲數據。

https://www.cwiki.us/display/ProtocolBuffers/Developer+Guide

相關文章
相關標籤/搜索