Protocol Buffers概覽
開發嚮導
歡迎來到protocol buffers的開發者文檔,protocol buffers是語言中立,平臺中立,易於擴展的結構化數據序列化方法,它可以用在通訊協議,數據存儲等方面。
這份文檔的目標讀者是試圖在應用中使用protocol buffers的Java, C++或者Pytho開發者。這份概覽告訴你如何開始-然後你可以去教程或者深入到protocol buffer編碼。API參考文檔同樣以三種語言提供,包括編寫.proto文件的編程語言和代碼風格指導。
什麼是protocol buffers?
Protocol buffers是一種可伸縮,高效的,自動化的結構化數據序列化機制,它比較像XML但是更小,更快,更簡單。定義好你的數據結構,然後你就可以使用生成的特殊的源代碼讀寫你的結構化數據,數據來源可以是各種數據流,也可以使用各種編程語言。你甚至可以在不破壞使用舊格式編譯並已經部署的程序的情況下更新數據結構。
他們如何工作的?
通過在.proto文件中定義protocol buffer消息類型,說明需要被序列化的信息需要保持什麼樣的結構。一個protocol buffer消息是一小片信息的邏輯記錄,包含一系列的名稱-值對。這裏是一個非常基礎的例子,他定義了包含個人信息的消息:
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消息類型(如上例)。你可以指明可選字段,必選字段和重複字段。關於編寫.proto文件的更多信息請見Protocol Buffer語言指導。
定義好消息後,就可以運行鍼對你的程序語言的protocol buffer編譯器來編譯.proto文件。這些類對每個字段提供簡單存取器(例如query()和set_query())和序列化整個結構到原生字節或從原生字節解析結構的方法的。然後你可以在程序中用這個Persion類生成,序列化或者從protocl buffer消息中取得Person對象。你可能寫這樣的代碼來操作:
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("[email protected]");
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 buffer代碼的完整的參考,在Protocol Buffer編碼有更多關於protocol buffer消息如何編碼的信息。
Why not just use XML?幹嘛不直接用XML?
相較於XML,Protocol buffers在序列化結構化數據方面有許多優點。它:
更簡單
3至10倍小
快20-100倍
更少的模糊性
對編程來講,生成數據訪問類更容易使用。
比如說,你想建模一個person,它有name和email。如果用XML,你需要寫:
John [email protected]
然而對應的protocol buffer消息( protocol buffer 文本格式)是這樣:
# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
name: "John Doe"
email: "[email protected]"
}
當這個消息被編碼爲二進制格式(文本格式)後,可能只有28字節長,並且解析只需要大約100-200納秒。XML的版本至少69字節不包括空格,需要花費5,000-10,000納秒解析。
Also, manipulating a protocol buffer is much easier:同樣,操作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好 - 例如,protocol buffers就不適合建模基於文本的有標記文檔(如HTML),因爲你很難在文字中插入結構信息。另外,XML是可讀的並且易於手工編輯的;protocol buffers,至少在原生格式上不是這樣。XML還是(某種程度上)自描述的。而protocol buffer僅僅在你有關於它的定義文件(.proto文件)的時候纔有意義。
聽起來對我有用!我怎麼開始用它?
下載軟件包 - 它包含了Java, Python, C++的protocol buffers編譯器的所有源代碼,還有用於I/O和測試的類。構建和安裝它的方法請參見附帶的README。
這些準備好以後,你就可以試試看針對你使用的編程語言的教程,它將帶你一步一步創建一個使用protocol buffers的簡單應用。
一點歷史
Protocol buffers最初是在Google開發出來處理一個索引服務器的request/response協議的。在protocol buffers以前,有一個手動marshalling/unmarshalling請求/響應的處理格式,結果是看起來非常醜陋的代碼,就像:
if(version ==3){
...
}elseif(version >4){
if(version ==5){
...
}
...
}
顯式的格式化的協議也會把新版本協議的發佈搞的很複雜,因爲開發者必須保證在請求發起者和實際處理者這兩端啓用新協議之前,它們之間的所有的服務器,都必須理解新版本的協議。
Protocol buffers被設計來解決許多這樣的問題:
新的字段可以很容易被引入,不需要檢查新增數據的中間服務器可以像之前一樣解析原有數據並一起傳輸他們,不需要知道新的字段。
格式是自描述的,可以被廣泛的編程語言處理(C++, Java, 等)
然而,用戶仍然需要手寫他們自己的解析代碼。
隨着系統的進化,它已經有了一些其他特性和用途:
自動生成的序列化和反序列化代碼,用戶可以不用手工編寫解析代碼了。
除了被用作短期的RPC(遠程過程調用)請求,人們開始用protocol buffers作爲一種便利的自描述格式來持久化存儲數據(比如Bigtable)。
服務器的RPC接口開始聲明成爲protocol文件的一個部分,還有protocol編譯器生成的類,用戶可以用實際的實現重寫他們。
Protocol buffers現在是Google交流數據的主要交際語 - 撰寫本文時,Google的代碼樹中有12,183個.proto文件,包含有48,162個不同的消息類型定義。它們被用在RPC系統和各種存儲系統的數據的持久化的存儲。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.