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

protocolbuffer(以下簡(jiǎn)稱(chēng)PB)是google 的一種數(shù)據(jù)交換的格式,它獨(dú)立于語(yǔ)言,獨(dú)立于平臺(tái)。google 提供了多種語(yǔ)言的實(shí)現(xiàn):java、c#、c++、go 和 python,每一種實(shí)現(xiàn)都包含了相應(yīng)語(yǔ)言的編譯器以及庫(kù)文件。由于它是一種二進(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é)議說(shuō)明

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

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

required:必須初始化字段,如果沒(méi)有賦值,在數(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ù)類(lèi)型

【protobuf使用和介紹】

2.ProtoBuf的使用流程

1.定義.proto文件
首先我們需要編寫(xiě)一個(gè) proto 文件,定義我們程序中需要處理的結(jié)構(gòu)化數(shù)據(jù),在 protobuf 的術(shù)語(yǔ)中,結(jié)構(gòu)化數(shù)據(jù)被稱(chēng)為 Message。proto 文件非常類(lèi)似 java 或者 C 語(yǔ)言的數(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è)成員,類(lèi)型為 int32 的 id,另一個(gè)為類(lèi)型為 string 的成員 str。opt 是一個(gè)可選的成員,即消息中可以不包含該成員。
2.編譯.proto文件
寫(xiě)好 proto 文件之后就可以用 Protobuf 編譯器將該文件編譯成目標(biāo)語(yǔ)言了??梢愿鶕?jù)不同的語(yǔ)言來(lái)選擇不同的編譯方式
在項(xiàng)目中我使用到的是分別是JavaScript和Java,前者是客戶(hù)端腳本語(yǔ)言,后者服務(wù)端語(yǔ)言。將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類(lèi)
        byte[] byteArray =person.toByteArray();
        Person p2 = Person.parseFrom(byteArray);
        System.out.println("after :" +p2.toString());
    }
}
輸出結(jié)果圖

從上面可以總結(jié)出protobuf的使用過(guò)程可以分為以下三個(gè),準(zhǔn)備好數(shù)據(jù),通過(guò)build()方法來(lái)組裝成protobuf包,然后通過(guò)toByteArray()來(lái)將protobuf轉(zhuǎn)換成二進(jìn)制序列流文件(序列化)。
反序列化的過(guò)程剛好與之相反,接收到的二進(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)無(wú)關(guān),語(yǔ)言無(wú)關(guān),可擴(kuò)展;
  • 提供了友好的動(dòng)態(tài)庫(kù),使用簡(jiǎn)單;
  • 解析速度快,比對(duì)應(yīng)的XML快約20-100倍;
  • 序列化數(shù)據(jù)非常簡(jiǎn)潔、緊湊,與XML相比,其序列化之后的數(shù)據(jù)量約為1/3到1/10。

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

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

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

《Google Protocol Buffer 的使用和原理》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容