Protobuf開發者指南

argf6921 8年前發布 | 9K 次閱讀 JavaScript開發 protobuf

本文檔是為那些想要在自己的應用中使用 Protocol Buffers 的Java、C++或Python開發者而寫的。這份概述介紹 Protocol Buffers ,并告訴你如何將它用起來——然后你可以通過 教程 繼續學習,或深入了解 Protocol Buffers 編碼規則 。

什么是Protocol Buffers?

Protocol Buffers是一個序列化結構化數據的靈活、高效且自動化的機制——類似XML,但更小,更快,更簡單。你定義一次結構化你的數據的方式,然后使用特別生成的代碼簡單地寫入,或使用不同的語言從大量的數據流讀出你的結構化數據。你甚至可以更新你的數據結構而不破壞已部署的基于 格式編譯的程序。

它們如何工作的?

通過在 .proto 文件中定義 Protocol Buffers 消息類型來描述你想要結構化你在序列化的信息的方式。每個 Protocol Buffers 消息是一個信息的小邏輯記錄,包含一系列名-值對。這里是一個非常基本的 .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;
}

如你所見,消息的格式很簡單——每個消息類型具有一個或多個唯一編號的字段,每個字段具有一個名和一個值,其中值類型可以是數字(整數或浮點數),布爾值,字符串,原始的字節,或者甚至是(如上面的例子所示)其它的Protocol Buffer消息類型,這允許層次式地結構化你的數據。你可以指定可選的字段、 必需的字段 ,和重復的字段。你可以在 Protocol Buffer 語言指南 找到更多關于編寫 .proto 文件的信息。

一旦定義好消息,你就可以運行 Protocol Buffer 編譯器為你的 .proto 文件產生應用程序的語言的數據訪問類。這為每個字段提供了簡單的訪問器 (如 name()set_name() ),以及將整個結構序列化為原始字節,或從原始字節解析為結構的方法——因而,比如你選擇C++,為上面的例子運行編譯器將產生名為Person的類。然后你可以在你的應用程序中使用這個類,來放置、序列化和提取Person Protocol Buffer 消息。然后你可以編寫如下這樣的代碼:

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 參考 找到使用生成的 Protocol Buffers 代碼的完整參考,你可以在 Protocol Buffer編碼 中找到更多關于 Protocol Buffers 消息編碼的內容。

為什么不使用XML呢?

在序列化數據方面,相對于XML, Protocol Buffers 有許多有點。 Protocol Buffers

  • 更簡單
  • 小3至10倍
  • 快20至100倍
  • 更少歧義
  • 產生數據訪問類方便編程使用

比如,你想要為 person 建模,它有一個 name 字段和一個 email 字段。在XML中,你需要:

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

而對應的 Protocol Buffers 消息 (以 Protocol Buffers 的 文本格式 描述) 則是:

# 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 Buffers 的 二進制格式 (上邊的文本格式只是為了方便調試和編輯的人類可讀的表示),它可能是28字節長,并需要大概100-200 納秒來解析。如果移除空白符的話,XML版本至少需要69字節,并需要大概 5,000-10,000 納秒來解析。

管理一個 Protocol Buffers 更簡單:

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好——比如, Protocol Buffers 不是建模 含有標記的基于文本的文檔 (如HTML) 的好方法,因為你不能簡單地交叉含有文本的結構,此外,XML是人類可讀且人類可編輯的; Protocol Buffers ,至少在它們的本地格式,不是。XML還——在一定程度上——是自描述的。 Protocol Buffers 只在你有消息定義 (.proto 文件) 時才有意義。

聽起來正是我想要的方案!我要如何將它用起來呢?

下載 Protocol Buffers 包 ——其中包含完整的Java、Python和C++ Protocol Buffers 編譯器的代碼,還包含你可以用于I/O測試的類。要構建并安裝你的編譯器,請依照README的指導進行。

一旦都設置好了,則可以試著按照 你選擇的語言的 教程 繼續學習 ——這將帶你創建一個使用 Protocol Buffers 的簡單應用。

proto3簡介

我們最近的版本 3 發布 引入了一個新的語言版本 - Protocol Buffers 語言版本 3 (亦稱proto3),并在我們已有的語言版本 (亦稱proto2) 引入了一些新功能。Proto3簡化了 Protocol Buffers 語言,使使用變得更簡單,并可以在更廣泛的語言中使用:我們當前的發行版讓你可以為Java,C++,Python,Java Lite,Ruby,JavaScript,Objective-C,和C#產生 Protocol Buffers 代碼。此外,你可以使用最新的Go protoc插件為Go產生proto3代碼,可在 golang/protobuf Github 倉庫找到。更多語言還在計劃中。

當前我們建議只試用proto3:

  • 如果你想要試用我們新支持的語言。
  • 如果你想要使用我們的新開源RPC實現 gRPC – 我們建議為所有的新gRPC服務器和客戶端使用proto3,以避免出現兼容性問題。

注意,兩個語言版本的APIs不完全兼容。為了避免給現有用戶造成不便,我們將在新的 Protocol Buffers 發行版中繼續支持之前的語言版本。

你可以在 發行說明 中查看當前默認版本的主要差異,并在 Proto3語言指南 學習關于proto3語法的內容。完整的proto3文檔很快就要到來了!

(如果說名字proto2和proto3似乎有點混亂,那是由于我們最初在開源 Protocol Buffers 時,它實際上是Google的第二個語言版本——也被稱為proto2。這也是為什么我們的開源版本號是從v2.0.0開始的)。

歷史

Protocol Buffers最初是在Google開發的,用來處理一個索引服務器請求/響應協議。在 Protocol Buffers 之前,有一個請求和響應的格式用于手動序列化/反序列化請求和響應,而且它支持協議的大量版本。這導致了一些非常丑陋的代碼,比如:

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

顯式地格式化協議也使新協議版本的上線很復雜,因為開發者不得不在他們切換到新協議之前,確保所有發起請求的服務器和實際處理請求的服務器理解新協議。

Protocol Buffers設計來解決許多這些問題:

  • 可以簡單地引入新字段,無需深入理解數據的中間服務器可以簡單地解析并傳遞數據而無需知道所有的字段。
  • 格式更加具有自描述性,且可由大量的語言 (C++,Java,等等) 處理。

然而,用戶依然需要手寫它們自己的解析代碼。

隨著系統的發展,它得到了大量的其它功能及使用:

  • 自動生成序列化和反序列化的代碼以避免手動解析。
  • 此外被用于短暫的 RPC (Remote Procedure Call) 請求,人們開始使用 Protocol Buffers 作為持久存儲數據的便利的自描述格式。
  • 服務器RPC接口開始被聲明為協議文件的一部分,并以協議編譯器生成stub類,用戶可以以服務器的接口的實際實現覆蓋。

    Protocol Buffers現在是Google的數據的通用語言——在寫作本文的時候,有48,162個不同的消息類型定義在Google代碼庫的12,183 個 .proto 文件中。它們同時在RPC系統及不同的存儲系統的數據存儲中使用。

 

來自:http://www.jianshu.com/p/3ab14a2cb477

 

 本文由用戶 argf6921 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!