歡迎來到 protocol buffers 的開發(fā)者指南。protocol buffers 是一個(gè)語言中立,平臺(tái)中立針對(duì)通訊協(xié)議,數(shù)據(jù)存儲(chǔ)和其他領(lǐng)域中對(duì)結(jié)構(gòu)化數(shù)據(jù)進(jìn)行序列化的擴(kuò)展方法。

本文檔主要針對(duì)的是 Java,C++ 或 Python 的開發(fā)人員希望在開發(fā)的應(yīng)用程序中使用 Protocol Buffers。這個(gè)有關(guān) Protocol Buffers 摘要性的介紹將會(huì)告訴你如何開始使用 Protocol Buffers。
如果你希望更加深入的了解有關(guān) Protocol Buffers 的內(nèi)容,你可以進(jìn)入 tutorials 或者 protocol buffer encoding 頁面來詳細(xì)了解。
有關(guān) API 的參考文檔,請(qǐng)參考頁面:reference documentation 這里提供了所有這 3 種語言的參考,同時(shí)也針對(duì) .proto language 和 style 提供相關(guān)的指南。
什么是 Protocol Buffers
Protocol buffers 是對(duì)結(jié)構(gòu)化數(shù)據(jù)序列化的一個(gè)靈活,高效,自動(dòng)化工具 —— 你可以將 Protocol buffers 想象成 XML,但是體積更小,更快也更加簡(jiǎn)單。
你可以自己定義你的結(jié)構(gòu)化數(shù)據(jù),然后你可以使用特定的代碼生成工具來非常容易對(duì)你的結(jié)構(gòu)化數(shù)據(jù)進(jìn)行讀取和寫入。這些數(shù)據(jù)的讀取和寫入可以是一系列的數(shù)據(jù)流和使用不同的計(jì)算機(jī)程序語言。
你甚至可以在不對(duì)已經(jīng)部署的程序進(jìn)行破壞的情況下更新你的數(shù)據(jù)結(jié)構(gòu)。
Protocol Buffers 是如何進(jìn)行工作的
你需要制定你希望如何將你的數(shù)據(jù)進(jìn)行序列化。你是通過 proto 文件來定義你的消息結(jié)構(gòu)化數(shù)據(jù)的。
每一 protocol buffer message 是一個(gè)小的信息記錄邏輯,這個(gè)消息中包含有一系列的名字,變量對(duì)照序列。
下面是一些基本的.proto 文件,這些文件中定義了一個(gè)消息,這個(gè)消息包含有一個(gè) person 信息:
messagePerson {requiredstring name =1;requiredint32 id =2;optionalstring email =3;enumPhoneType {MOBILE=0;HOME=1;WORK=2;? }messagePhoneNumber {requiredstring number =1;optionalPhoneType type =2[default = HOME];? }repeatedPhoneNumber phone =4;}
通過上面你可以看到這個(gè)消息的格式非常簡(jiǎn)單—— 每一個(gè)消息類型都有一個(gè)或者多個(gè)唯一進(jìn)行編號(hào)的字段,每一個(gè)字段包含有一個(gè)名字和變量類型。
變量可以為數(shù)字(整形或者浮點(diǎn)型)(numbers),布爾類型(booleans),字符串(strings),原生二進(jìn)制(raw bytes)甚至其他的 protocol buffer 消息類型,能夠允許你分級(jí)的結(jié)構(gòu)化你的數(shù)據(jù)。
你可以將字段指定為可選字段(optional fields),必須字段(required fields)和重復(fù)字段(repeated fields)。你可以從下面的 Protocol Buffer Language Guide 頁面中找到更多有關(guān) .proto 的定義。
一旦你成功定義了你的消息,你可以針對(duì)你使用的語言使用你定義的 .proto 來運(yùn)行 protocol buffer 編譯器(protocol buffer compiler)來生成數(shù)據(jù)訪問類。
針對(duì)每一個(gè)字段,在數(shù)據(jù)訪問類中提供了簡(jiǎn)單的訪問方法(例如 name() 和 set_name())和序列化到原生 2 進(jìn)制數(shù)據(jù)和從原生 2 進(jìn)制數(shù)據(jù)反序列化的方法。
針對(duì)上面的定義,如果你現(xiàn)在使用的是 C++ 語言的話,當(dāng)你把消息定義進(jìn)行編譯后,你將會(huì)得到一個(gè)稱為 Person 的類。對(duì)數(shù)據(jù)進(jìn)行序列化和從序列化的數(shù)據(jù)中(protocol buffer 消息)重新獲得 Person 數(shù)據(jù)。
然后你可以寫一些類似 Person person; 的代碼。
Person person;person.set_name("John Doe");person.set_id(1234);person.set_email("jdoe@example.com");fstreamoutput("myfile", ios::out | ios::binary);person.SerializeToOstream(&output);
隨后,你可以對(duì)消息進(jìn)行讀取:
fstreaminput("myfile", ios::in | ios::binary);Person person;person.ParseFromIstream(&input);cout<<"Name: "<< person.name() <
你可以向你的消息中添加新的字段而不會(huì)損壞老的消息。這是因?yàn)樵诶系南⑻幚碇校槍?duì)新的字段是完全忽略掉的。因此,如果你在你的通訊協(xié)議中使用 protocol buffers 為數(shù)據(jù)結(jié)構(gòu)的話,
你可以對(duì)你的協(xié)議和消息進(jìn)行擴(kuò)展而不需要擔(dān)心老的代碼沒有辦法編譯通過,或者損壞老的代碼。
你可以訪問 API Reference section 頁面中的內(nèi)容來了解完整 protocol buffer 代碼的生成和使用。
你也可以在 Protocol Buffer Encoding 頁面中了解更多protocol buffer 消息是如何進(jìn)行編碼的。
為什么不使用 XML
針對(duì) XML 來說 Protocol Buffers 具有更多的優(yōu)勢(shì)來對(duì)序列化結(jié)構(gòu)數(shù)據(jù)。
更加簡(jiǎn)單
小于 XML 3 到 10 倍
快于 XML 20 到 100 倍
松耦合
使用程序工具來創(chuàng)建數(shù)據(jù)訪問類,使數(shù)訪問類更加簡(jiǎn)單
假設(shè),你需要講 person 這個(gè)數(shù)據(jù)進(jìn)行定義,在 XML 你需要使用:
John Doejdoe@example.com
來進(jìn)行定義。
在 Protocol Buffers 中針對(duì)上面的消息文本化(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"}
當(dāng)上面的消息被編碼為 Protocol Buffer 二進(jìn)制格式(binary format)上面的文字可能小于 28 bytes,并且可能需要 100-200 納秒(nanoseconds)來進(jìn)行處理。
我們將上面轉(zhuǎn)換為可以人為讀取的目的主要是為進(jìn)行調(diào)試和編輯。
如果你使用 XML 的話,上面的信息至少需要 69 bytes (你需要?jiǎng)h除所有的空格),同時(shí)你需要 5,000-10,000 納秒(nanoseconds)來進(jìn)行處理。
同時(shí),對(duì) protocol buffer 進(jìn)行操作也是非常容易的:
cout<<"Name: "<< person.name() <
如果使用的是 XML 的話,你需要進(jìn)行下面的操作:
cout<<"Name: "<< person.getElementsByTagName("name")->item(0)->innerText()? ? <item(0)->innerText()? ? <
但是,protocol buffers 并不是任何時(shí)候都會(huì)比 XML 好。例如,針對(duì)基于文本的標(biāo)記語言(例如,XML),protocol buffers 就不是一個(gè)很好的選項(xiàng),
因?yàn)槟悴荒苁褂?protocol buffer 更好的在文檔中進(jìn)行交換。更主要的是 HTML 是人類可以閱讀和編輯的。protocol buffer 也不是不可以人為的讀取,但是針對(duì)原生的 protocol buffer 格式是沒有辦法人為進(jìn)行讀取和編輯的。
XML 與 HTML 一樣,在某種程度上是一種自我描述數(shù)據(jù)。protocol buffer 只針對(duì)你在 .proto 文件中描述的內(nèi)容進(jìn)行表達(dá)。
看起來像一個(gè)解決方案,我應(yīng)該如何開始呢
Download the package – 這包中含有針對(duì) Java, Python, 和 C++ protocol buffer 編譯器源代碼,和你需要進(jìn)行 I/O 和測(cè)試的類。希望對(duì)你的編譯器進(jìn)行編譯和構(gòu)建,請(qǐng)參考代碼中的 README 文件。
一旦你完成了所有的設(shè)置,請(qǐng)參考 tutorial 頁面中的內(nèi)容來選擇你需要的語言——這個(gè)能夠幫助你使用 protocol buffer 創(chuàng)建一個(gè)簡(jiǎn)單的應(yīng)用程序。
介紹 proto3
在我們最新的 version 3 發(fā)行版 中推出了新的語言版本 —— Protocol Buffers language version 3(另稱 proto3),在這個(gè)版本中針對(duì)我們已經(jīng)存在的語言版本(proto2)使用了一些新的特性。
Proto3 簡(jiǎn)化了 protocol buffer 語言,使其更加容易使用并且能夠支持更多的語言:我們當(dāng)前發(fā)行的 proto3 能夠讓你創(chuàng)建 Java, C++, Python, Java Lite, Ruby, JavaScript, Objective-C, and C#。
另外你也可以通過使用 Go protoc 插件來用 proto3 創(chuàng)建 Go 代碼,這個(gè)插件你可以到 golang/protobuf Github 中下載到。更多的語言還在逐步進(jìn)行支持中。
請(qǐng)注意,這 2 個(gè)版本的 API 并不是完全兼容的。為了照顧還在使用老版本的用戶,我們將會(huì)在新的 protocol buffers 發(fā)行中同時(shí)支持老的版本。
你可以在下面的發(fā)行日志(release notes)查看 2 個(gè)版本的主要不同。有關(guān) proto3 的句法,請(qǐng)參考 Proto3 Language Guide 中的內(nèi)容,針對(duì) proto3 的完整文檔還沒有編寫完成,將會(huì)隨后推出。
看起來 proto2 和 proto3 可能會(huì)產(chǎn)生一些混淆,這是因?yàn)樵嫉拈_源 protocol buffers 實(shí)際上是 Google 內(nèi)部語言的第二個(gè)版本,同時(shí)我們的開源版本也是從 v2.0.0 開始的。
簡(jiǎn)單來說就是 proto 最開始的版本是 Google 內(nèi)部使用的,在 proto 第二個(gè)版本的時(shí)候,Google 決定進(jìn)行開源了,所以開源的 proto 是從 proto2 開始的。
一個(gè)簡(jiǎn)短的歷史
Protocol buffers 最開始是在 Google 內(nèi)部進(jìn)行開發(fā)的,用于處理在索引服務(wù)器上請(qǐng)求/響應(yīng)(request/response)的協(xié)議。
在 Protocol buffers 之前,針對(duì)請(qǐng)求和響應(yīng),使用的是 marshalling/unmarshalling,這個(gè)能夠支持一系列的協(xié)議。但是結(jié)果看起來卻是非常的難看,例如:
if(version ==3) {? ...}elseif(version >4) {if(version ==5) {? ? ...? }? ...}
明確格式化的的協(xié)議也使新版本的協(xié)議更加難以推出,這是因?yàn)殚_發(fā)者必須能夠了解老協(xié)議在服務(wù)器之間是如何進(jìn)行處理的,同時(shí)也需要了解新的協(xié)議。只有對(duì)新老協(xié)議都有所了解后才能逐步使用新的協(xié)議替換老的協(xié)議。
Protocol buffers 被用來設(shè)計(jì)解決上面的很多問題:
新的字段比較能夠容易的進(jìn)行定義,中級(jí)服務(wù)器不需要對(duì)數(shù)據(jù)進(jìn)行檢查,直接對(duì)數(shù)據(jù)進(jìn)行處理,同時(shí)也可以直接傳輸數(shù)據(jù)而不需要了解數(shù)據(jù)是如何進(jìn)行定義的。
格式使用自描述,能夠更加容易支持更多的語言(C++,Java 等)。
但是,用戶還是需要手動(dòng)書寫他們自己的處理diam。
作為系統(tǒng)的進(jìn)化來說,它獲得了許多其他的特性和用途:
自動(dòng)生成序列化和反序列化代碼而避免手動(dòng)書寫這些代碼。
除了開始使用短期RPC(遠(yuǎn)程過程調(diào)用)請(qǐng)求,人們開始使用 protocol buffers 作為高效的自描述結(jié)構(gòu)化數(shù)據(jù)格式(主要針對(duì)數(shù)據(jù)短期存在,例如在 Bigtable)。
服務(wù)器RPC接口開始被聲明為協(xié)議文件的一部分,協(xié)議編譯器生成根類,用戶可以通過服務(wù)器接口的實(shí)現(xiàn)和重載它們。
Protocol buffers 在 Google 中成為針對(duì)數(shù)據(jù)的通用語言—— 隨著時(shí)間的流逝,在 Google 內(nèi)部已經(jīng)有超過 348,952 .proto 文件被定義。這些被用在 RPC 系統(tǒng)和存儲(chǔ)系統(tǒng)中存儲(chǔ)數(shù)據(jù)。