protocol buffers使用说明
一、什么是protocol buffers
Protocol buffers是一個(gè)靈活的、高效的、自動(dòng)化的用于對(duì)結(jié)構(gòu)化數(shù)據(jù)進(jìn)行序列化的協(xié)議,與XML相比,Protocol buffers序列化后的碼流更小、速度更快、操作更簡(jiǎn)單。你只需要將要被序列化的數(shù)據(jù)結(jié)構(gòu)定義一次(譯注:使用.proto文件定義),便可以使用特別生成的源代碼(譯注:使用protobuf提供的生成工具)輕松的使用不同的數(shù)據(jù)流完成對(duì)這些結(jié)構(gòu)數(shù)據(jù)的讀寫操作,即使你使用不同的語(yǔ)言(譯注:protobuf的跨語(yǔ)言支持特性)。你甚至可以更新你的數(shù)據(jù)結(jié)構(gòu)的定義(譯注:就是更新.proto文件內(nèi)容)而不會(huì)破壞依賴“老”格式編譯出來的程序。
二、protocol buffers的工作流程
首先,你需要通過在.proto文件中定義protocol buffer的message類型來指定你想要序列化的數(shù)據(jù)結(jié)構(gòu),每一個(gè)protocol buffer message是一個(gè)邏輯上的信息記錄,它包含一系列的鍵值對(duì)。這里展示一個(gè)最基本的.ptoto文件的例子,它定義了一個(gè)包含Person信息的message:
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; }正如你所看見的那樣,message的格式非常簡(jiǎn)單–每一個(gè)message類型都有一個(gè)或多個(gè)帶有唯一編號(hào)的字段,每一個(gè)字段有一個(gè)字段名和一個(gè)字段類型,字段類型可以是數(shù)值類型(比如整形或浮點(diǎn)型)、booleans(布爾類型)、strings(字符串類型)、raw bytes、甚至(正如上面的例子)還可以是其他的protocol buffer message類型,這允許你可以分層次的組織你的數(shù)據(jù)結(jié)構(gòu)。你可以單獨(dú)指定每一個(gè)字段為optional fields(可選字段)、required fields(必須字段)、repeated fields(可重復(fù)字段)。下一篇博文將會(huì)對(duì).proto文件進(jìn)行更詳細(xì)的描述。
一旦定義了你的message,你就可以根據(jù)你所使用的語(yǔ)言(譯注:如JAVA、C++、Python等)使用protocol buffer提供的編譯工具編譯.proto文件生成數(shù)據(jù)訪問類。這些類為每一個(gè)字段都提供了簡(jiǎn)單的訪問器(比如name()和set_name()),同時(shí)還提供了將整個(gè)結(jié)構(gòu)化數(shù)據(jù)序列化為原始字節(jié)數(shù)據(jù)以及從原始字節(jié)數(shù)據(jù)反序列化為結(jié)構(gòu)化數(shù)據(jù)的方法(譯注:C++中稱之為函數(shù))。例如,如果你使用的語(yǔ)言是C++,運(yùn)行編譯器編譯上述的例子將生成一個(gè)名為Person的類,在你的應(yīng)用程序中你可以使用這個(gè)類來填充、序列化和反序列化Person protocol buffer messages。之后你可能會(huì)寫下如下類似的代碼(譯注:序列化):
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);之后,你可以將你的message讀回(譯注:反序列化):
fstream input("myfile", ios::in | ios::binary); Person person; person.ParseFromIstream(&input); cout << "Name: " << person.name() << endl; cout << "E-mail: " << person.email() << endl;你可以向你的message中添加新的字段而不會(huì)破壞前向兼容性;在解析時(shí)舊的二進(jìn)制文件會(huì)簡(jiǎn)單的忽略掉新字段,所以,如果你的通信協(xié)議中使用protocol buffers作為數(shù)據(jù)交換格式,那么你可以擴(kuò)展你的協(xié)議而不用擔(dān)心會(huì)打亂現(xiàn)有的代碼。
三、為什么不使用XML?
相對(duì)于XML,protocol buffers在序列化結(jié)構(gòu)數(shù)據(jù)時(shí)擁有許多先進(jìn)的特性:
1、更簡(jiǎn)單
2、序列化后字節(jié)占用空間比XML少3-10倍
3、序列化的時(shí)間效率比XML快20-100倍
4、具有更少的歧義性
5、自動(dòng)生成數(shù)據(jù)訪問類方便應(yīng)用程序的使用
舉個(gè)例子,如果你想描述一個(gè)具有name和email的person數(shù)據(jù)結(jié)構(gòu),在XML中,你需要這樣做:
<person><name>John Doe</name><email>jdoe@example.com</email></person>然而,在protocol buffers的message中(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" }當(dāng)這個(gè)message被編碼成protocol buffer的二進(jìn)制格式(上述的文本格式只是為了方便閱讀、調(diào)試和編輯),它將可能占用28個(gè)字節(jié)長(zhǎng)度并且僅需要100-200納秒的解析時(shí)間。相比,XML版本的則至少需要占用69字節(jié)的空間(這是在移除XML中的空格、換行之后),同時(shí),將耗費(fèi)大約5000-10000納秒的解析時(shí)間。
除此之外,手動(dòng)操作protocol buffer更為方便,例如如下C++代碼:
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;事物總有兩面性,和XML相比protocol buffers并不總是更好的選擇,例如,protocol buffers并不適合用來描述一個(gè)基于文本的標(biāo)記型文檔(比如HTML),因?yàn)槟銦o(wú)法輕易的交錯(cuò)文本的結(jié)構(gòu)。另外,XML具有很好的可讀性和可編輯性;而protocol buffers,至少在它們的原生形式上并不具備這個(gè)特點(diǎn)。XML同時(shí)也是可擴(kuò)展、自描述的。而一個(gè)protocol buffer只有在具有message 定義(在.proto文件中定義)時(shí)才會(huì)有意義。
四、如何開始使用protocol buffers?
首先,可以在這里下載安裝包或者源碼包
https://developers.google.com/protocol-buffers/docs/downloads#release-packages
這包含了針對(duì)JAVA、Python和C++編譯器的完整源碼,同時(shí)包含了你所需要的I/O和測(cè)試類。為了完成編譯和安裝,請(qǐng)參照README文件。
一旦你完成了編譯和安裝,那么就可以開始使用protocol buffers了,后續(xù)的博文將會(huì)對(duì)C++和JAVA語(yǔ)言的具體使用細(xì)節(jié)進(jìn)行闡述。
五、proto3介紹
我們最新的版本version 3 alpha release引進(jìn)了一個(gè)新的語(yǔ)言版本–Protocol Buffers version 3 (稱之為proto3),它在我們現(xiàn)存的語(yǔ)言版本(proto2)上引進(jìn)了一些新特性。proto3簡(jiǎn)化了protocol buffer language,這使其可以更便于使用和支持更多的編程語(yǔ)言:我們現(xiàn)在的alpha release版本可以讓你能產(chǎn)生JAVA、C++、Pthyon、JavaNano、Ruby、Objective-C和C#版本的protocol buffer code,不過可能有時(shí)會(huì)有一些局限性。另外,你可以使用最新的Go protoc插件來產(chǎn)生Go語(yǔ)言版本的proto3 code,這可以從golang/protobuf Github repository獲取。
我們現(xiàn)在只推薦你使用proto3:
1、如果你想嘗試在我們新支持的語(yǔ)言中使用protocol buffers
2、如果你想嘗試我們最新開源的RPC實(shí)現(xiàn)gRPC(目前仍處于alpha release版本),我們建議你為所有的gRPC 服務(wù)器和客戶端都使用proto3以避免兼容性問題。
注意兩個(gè)版本的語(yǔ)言APIs并不是完全兼容的,為了避免給原來的用戶造成不便,我們將會(huì)繼續(xù)維護(hù)之前的那個(gè)版本(譯注:proto2)。
六、最后說一點(diǎn)歷史
Protocol buffers最初被Google開發(fā)用來作為處理索引服務(wù)器的request/response協(xié)議。在protocol buffers誕生之前,有一個(gè)需要手動(dòng)編碼/解碼requests、responses的協(xié)議,這個(gè)協(xié)議支持一個(gè)數(shù)字版本號(hào),這導(dǎo)致了一個(gè)非常丑陋的代碼,如下所示:
if (version == 3) {...} else if (version > 4) {if (version == 5) {...}...}很顯然的,格式化的協(xié)議也導(dǎo)致了復(fù)雜的新版本推出問題,因?yàn)殚_發(fā)人員必須確保所有服務(wù)器請(qǐng)求的發(fā)起者和實(shí)際的請(qǐng)求處理者之間都要理解新的協(xié)議。
Protocol buffers就是用來解決這些問題的:
1、可以很容易的插入新字段,中間的服務(wù)器可以簡(jiǎn)單的解析它而不需要了解所有字段。
2、格式更具有自描述性,可以被不同的語(yǔ)言處理(比如JAVA、C++、Python等)。
3、自動(dòng)產(chǎn)生序列化和反序列化代碼從而避免了手動(dòng)解析。
4、除了應(yīng)用在具有短暫生命周期的RPC請(qǐng)求中,人們開始使用protocol buffers 作為一種便利的自描述格式來存儲(chǔ)數(shù)據(jù)(比如在Bigtable中)。
5、服務(wù)器的RPC接口開始被聲明為協(xié)議文件的一部分,通過protocol 編譯器產(chǎn)生stub類,該類可以被用戶根據(jù)實(shí)際實(shí)現(xiàn)的服務(wù)器接口進(jìn)行重寫。
總結(jié)
以上是生活随笔為你收集整理的protocol buffers使用说明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android c 对象为空,ndk-j
- 下一篇: android连接耳机时音量控制,and