詳解通信數(shù)據(jù)協(xié)議ProtoBuf

protocolbuffer(以下簡(jiǎn)稱PB)是google 的一種數(shù)據(jù)交換的格式仅叫,它獨(dú)立于語言膏斤,獨(dú)立于平臺(tái)盅惜。google 提供了多種語言的實(shí)現(xiàn):java中剩、c#、c++抒寂、go 和 python结啼,每一種實(shí)現(xiàn)都包含了相應(yīng)語言的編譯器以及庫文件。由于它是一種二進(jìn)制的格式屈芜,比使用 xml 進(jìn)行數(shù)據(jù)交換快許多郊愧。可以把它用于分布式應(yīng)用之間的數(shù)據(jù)通信或者異構(gòu)環(huán)境下的數(shù)據(jù)交換井佑。作為一種效率和兼容性都很優(yōu)秀的二進(jìn)制數(shù)據(jù)傳輸格式属铁,可以用于諸如網(wǎng)絡(luò)傳輸、配置文件躬翁、數(shù)據(jù)存儲(chǔ)等諸多領(lǐng)域焦蘑。

1.ProtoBuf協(xié)議說明

proto文件定義了協(xié)議數(shù)據(jù)中的實(shí)體結(jié)構(gòu)(message ,field)

  • 關(guān)鍵字message: 代表了實(shí)體結(jié)構(gòu),由多個(gè)消息字段(field)組成姆另。
  • 消息字段(field): 包括數(shù)據(jù)類型喇肋、字段名坟乾、字段規(guī)則迹辐、字段唯一標(biāo)識(shí)、默認(rèn)值
  • 數(shù)據(jù)類型:如下圖所示
  • 字段規(guī)則:

required:必須初始化字段甚侣,如果沒有賦值明吩,在數(shù)據(jù)序列化時(shí)會(huì)拋出異常
optional:可選字段,可以不必初始化殷费。
repeated:數(shù)據(jù)可以重復(fù)(相當(dāng)于java 中的Array或List)
字段唯一標(biāo)識(shí):序列化和反序列化將會(huì)使用到印荔。

  • 默認(rèn)值:在定義消息字段時(shí)可以給出默認(rèn)值低葫。
數(shù)據(jù)類型

【protobuf使用和介紹】

2.ProtoBuf的使用流程

1.定義.proto文件
首先我們需要編寫一個(gè) proto 文件,定義我們程序中需要處理的結(jié)構(gòu)化數(shù)據(jù)仍律,在 protobuf 的術(shù)語中嘿悬,結(jié)構(gòu)化數(shù)據(jù)被稱為 Message。proto 文件非常類似 java 或者 C 語言的數(shù)據(jù)定義水泉。下面代碼顯示了例子應(yīng)用中的 proto 文件內(nèi)容:

package lm; 
message helloworld 
{ 
   required int32     id = 1;  // ID 
   required string    str = 2;  // str 
   optional int32     opt = 3;  //optional field 
}

一個(gè)比較好的習(xí)慣是認(rèn)真對(duì)待 proto 文件的文件名善涨。比如將命名規(guī)則定于如下:

packageName.MessageName.proto

在上例中,package 名字叫做 lm草则,定義了一個(gè)消息 helloworld钢拧,該消息有三個(gè)成員,類型為 int32 的 id炕横,另一個(gè)為類型為 string 的成員 str源内。opt 是一個(gè)可選的成員,即消息中可以不包含該成員份殿。
2.編譯.proto文件
寫好 proto 文件之后就可以用 Protobuf 編譯器將該文件編譯成目標(biāo)語言了膜钓。可以根據(jù)不同的語言來選擇不同的編譯方式
在項(xiàng)目中我使用到的是分別是JavaScript和Java伯铣,前者是客戶端腳本語言呻此,后者服務(wù)端語言。將proto文件編譯生成java文件腔寡,這里有一個(gè)很好的案例:《Protobuf協(xié)議的Java應(yīng)用例子》焚鲜,當(dāng)然在項(xiàng)目中一般是不會(huì)這么干的,
3.序列化和反序列化

public class Test {
    public static void main(String[] args) throws IOException {
        //模擬將對(duì)象轉(zhuǎn)成byte[]放前,方便傳輸
        PersonEntity.Person.Builder builder = PersonEntity.Person.newBuilder();
        builder.setId(1);
        builder.setName("ant");
        builder.setEmail("ghb@soecode.com");
        PersonEntity.Person person = builder.build();
        System.out.println("before :"+ person.toString());

        System.out.println("===========Person Byte==========");
        for(byte b : person.toByteArray()){
            System.out.print(b);
        }
        System.out.println();
        System.out.println(person.toByteString());
        System.out.println("================================");

        //模擬接收Byte[]忿磅,反序列化成Person類
        byte[] byteArray =person.toByteArray();
        Person p2 = Person.parseFrom(byteArray);
        System.out.println("after :" +p2.toString());
    }
}
輸出結(jié)果圖

從上面可以總結(jié)出protobuf的使用過程可以分為以下三個(gè),準(zhǔn)備好數(shù)據(jù)凭语,通過build()方法來組裝成protobuf包葱她,然后通過toByteArray()來將protobuf轉(zhuǎn)換成二進(jìn)制序列流文件(序列化)。
反序列化的過程剛好與之相反似扔,接收到的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制數(shù)組byte[]吨些,然后調(diào)用protobuf的parseFrom()方法即可實(shí)現(xiàn)反序列化。


序列化流程圖

3.protoBuf數(shù)據(jù)協(xié)議的優(yōu)勢(shì)

  • 平臺(tái)無關(guān)炒辉,語言無關(guān)豪墅,可擴(kuò)展;
  • 提供了友好的動(dòng)態(tài)庫黔寇,使用簡(jiǎn)單偶器;
  • 解析速度快,比對(duì)應(yīng)的XML快約20-100倍;
  • 序列化數(shù)據(jù)非常簡(jiǎn)潔屏轰、緊湊颊郎,與XML相比,其序列化之后的數(shù)據(jù)量約為1/3到1/10霎苗。

說明:
數(shù)據(jù)量小是因?yàn)槟房裕琍rotobuf 序列化后所生成的二進(jìn)制消息非常緊湊,這得益于 Protobuf 采用的非常巧妙的little-endian編碼方法唁盏。

轉(zhuǎn)換速度快猾编。首先我們來了解一下 XML 的封解包過程。XML 需要從文件中讀取出字符串升敲,再轉(zhuǎn)換為 XML 文檔對(duì)象結(jié)構(gòu)模型答倡。之后,再從 XML 文檔對(duì)象結(jié)構(gòu)模型中讀取指定節(jié)點(diǎn)的字符串驴党,最后再將這個(gè)字符串轉(zhuǎn)換成指定類型的變量瘪撇。這個(gè)過程非常復(fù)雜,其中將 XML 文件轉(zhuǎn)換為文檔對(duì)象結(jié)構(gòu)模型的過程通常需要完成詞法文法分析等大量消耗 CPU 的復(fù)雜計(jì)算港庄。

反觀 Protobuf倔既,它只需要簡(jiǎn)單地將一個(gè)二進(jìn)制序列,按照指定的格式讀取到 C++ 對(duì)應(yīng)的結(jié)構(gòu)類型中就可以了鹏氧。從上一節(jié)的描述可以看到消息的 decoding 過程也可以通過幾個(gè)位移操作組成的表達(dá)式計(jì)算即可完成渤涌。速度非常快把还。

《Google Protocol Buffer 的使用和原理》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末实蓬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吊履,更是在濱河造成了極大的恐慌安皱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艇炎,死亡現(xiàn)場(chǎng)離奇詭異酌伊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缀踪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門居砖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驴娃,你說我怎么就攤上這事奏候。” “怎么了托慨?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵鼻由,是天一觀的道長(zhǎng)暇榴。 經(jīng)常有香客問我厚棵,道長(zhǎng)蕉世,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任婆硬,我火速辦了婚禮狠轻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彬犯。我一直安慰自己向楼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布谐区。 她就那樣靜靜地躺著湖蜕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宋列。 梳的紋絲不亂的頭發(fā)上昭抒,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音炼杖,去河邊找鬼灭返。 笑死,一個(gè)胖子當(dāng)著我的面吹牛坤邪,可吹牛的內(nèi)容都是我干的熙含。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼艇纺,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼怎静!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起黔衡,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤消约,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后员帮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體或粮,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年捞高,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氯材。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡硝岗,死狀恐怖氢哮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情型檀,我是刑警寧澤冗尤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響裂七,放射性物質(zhì)發(fā)生泄漏皆看。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一背零、第九天 我趴在偏房一處隱蔽的房頂上張望腰吟。 院中可真熱鬧,春花似錦徙瓶、人聲如沸毛雇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灵疮。三九已至,卻和暖如春壳繁,著一層夾襖步出監(jiān)牢的瞬間始藕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工氮趋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伍派,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓剩胁,卻偏偏與公主長(zhǎng)得像诉植,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昵观,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容