Google Protocol buffer 學(xué)習(xí)筆記.上篇-簡(jiǎn)介 安裝 示例

本次分上下兩篇簡(jiǎn)單記錄自己對(duì)protobuf協(xié)議的學(xué)習(xí)筆記, 上篇簡(jiǎn)單介紹protobuf, 記錄了ubuntu系統(tǒng)中的安裝過(guò)程, 并舉了一個(gè)簡(jiǎn)單示例; 下篇將介紹protobuf的兩個(gè)重要機(jī)制, 動(dòng)態(tài)編譯與類(lèi)型反射.
能力有限, 如有疏漏望請(qǐng)指正.


引子

  • Google Protocol Buffer協(xié)議簡(jiǎn)稱(chēng)Protobuf, 是谷歌內(nèi)部的混合語(yǔ)言數(shù)據(jù)標(biāo)準(zhǔn)

  • 是一種高效輕便結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式, 可用于將結(jié)構(gòu)化數(shù)據(jù)串行化(序列化)

  • 適合用于數(shù)據(jù)存儲(chǔ)RPC數(shù)據(jù)交換格式(不同平臺(tái), 不同機(jī)器之間的信息傳遞), 可用于通訊協(xié)議, 數(shù)據(jù)存儲(chǔ)等領(lǐng)域的語(yǔ)言無(wú)關(guān), 平臺(tái)無(wú)關(guān), 可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式

  • 提供多種語(yǔ)言支持, C++, Java, Python, C# ...(protobuf2的話(huà)只支持前三種)

  • 缺陷 可讀性差, 因?yàn)槭且远M(jìn)制形式存放的, 如果不配合對(duì)應(yīng)的proto文件, 那么是無(wú)法看懂的. 這一點(diǎn)與XML截然相反(XML具有自描述性, 就是人能看懂的意思)

  • protobuf是一種序列化協(xié)議
  • 高效輕便
  • 支持多語(yǔ)言

一 簡(jiǎn)介(隨意跳過(guò))

  • 本小節(jié)本著不求甚解的原則簡(jiǎn)單講一下使得protobuf更高效輕便的技術(shù)

  • 其中1,1, 1.2, 1.3解釋了為什么protobuf序列化數(shù)據(jù)非常簡(jiǎn)潔、緊湊,與XML相比,其序列化之后的數(shù)據(jù)量約為1/3到1/10****

  • 其中1.4, 解釋了為什么****解析速度快,比XML快約20-100倍****

1.1 varint編碼方式

  • 用一個(gè)多個(gè)字節(jié)來(lái)表示一個(gè)數(shù)字, 值越小采用的字節(jié)數(shù)越少

  • 每個(gè)字節(jié)最高位用作標(biāo)記位, 如果該bit為1, 表示后續(xù)部分也是該數(shù)字的一部分; 如果該bit為0, 那么表示結(jié)束. (這一點(diǎn)是varint編碼的基本原理)

  • 采用小端字節(jié)序

image.png

1.2 Key-Pair存儲(chǔ)方式

  • 采用此種key-value格式無(wú)需使用分隔符來(lái)分隔不同的field

  • 通過(guò)key來(lái)標(biāo)識(shí)field, 通過(guò)對(duì)應(yīng)的key獲取到對(duì)應(yīng)的value

image.png

1.3 ZigZag編碼

  • 使用無(wú)符號(hào)數(shù)來(lái)表示有符號(hào)數(shù)

    • 正負(fù)數(shù)交替出現(xiàn)的方式
  • 優(yōu)點(diǎn) 絕對(duì)值較小的數(shù), 無(wú)論正負(fù), 所需要用的比特位都會(huì)較少, 充分利用了varint編碼的優(yōu)點(diǎn)

image.png

1.4 解封包機(jī)制

  • XML的解封包機(jī)制, XML需要從文件中讀取字符串, 然后轉(zhuǎn)換為XML文檔對(duì)象結(jié)構(gòu)模型, 再?gòu)脑撃P椭凶x取制定節(jié)點(diǎn)的字符串, 最后再將該字符串轉(zhuǎn)換為制定類(lèi)型的變量.

    • 總之很復(fù)雜啦
  • Protobuf的解封包機(jī)制, 經(jīng)由protobuf序列化得到的結(jié)構(gòu)是以二進(jìn)制的形式保存在文件中, 只需將對(duì)應(yīng)的二進(jìn)制讀取進(jìn)入C++結(jié)構(gòu)類(lèi)型中即可, 就是一個(gè)移位操作

    • 顯然更加高效, 當(dāng)然也造成了毫無(wú)自描述性的問(wèn)題...

二 安裝

  • 系統(tǒng) ubuntu-16.04.4

  • protobuf 此處安裝的protobuf3.6.0, github上隨便一搜就有啦

  1. 解壓, 切換至下載目錄 tar -xvf protobuf-all-3.6.0.tar.gz protobuf-3.6.0/ 根據(jù)不同格式選擇不同的解壓命令啦

  2. 切換至目標(biāo)目錄下cd protobuf-3.6.0/

  3. 觀(guān)察一下有沒(méi)有包含configure文件, 如果不存在那么先執(zhí)行./autogen.shshell腳本生成該文件

  4. ./configure此處可以通過(guò)后綴--prefix=$INSTALL_DIR來(lái)指定想要安裝的目標(biāo)目錄(將$INSTALL_DIR替換成自己想要的目錄就好啦), 如果不指定一般是安裝在默認(rèn)的/usr/local/lib

  5. make編譯一下, 等個(gè)十來(lái)分鐘吧

  6. make check

  7. make install安裝

  8. protoc --version檢查一下是否安裝成功, 成功會(huì)顯示版本號(hào), 多半會(huì)失敗啦, 那就看下一步

  9. 如果提示protoc: error while loading shared libraries: libprotoc.so.9: cannot open shared object file: No such file or directory, 那么是因?yàn)閜rotobuf的安裝路徑(默認(rèn)的/usr/local/lib)不在ubuntu體系中默認(rèn)的LD_LIBRARY_PATH中, 所以無(wú)法找到對(duì)應(yīng)的lib. 解決 只需要在/etc/ld.so.conf.d/目錄下創(chuàng)建文件bprotobuf.conf文件, 并寫(xiě)入我們的安裝路徑(/usr/local/lib), 然后執(zhí)行sudo ldconfig即可.

    • 其中ldconfig是一個(gè)動(dòng)態(tài)鏈接庫(kù)管理命令,為了讓動(dòng)態(tài)鏈接庫(kù)為系統(tǒng)所共享
      • /lib/usr/lib中添加動(dòng)態(tài)庫(kù), 那么只需要執(zhí)行ldconfig即可
      • 除了此二目錄以外的位置增加動(dòng)態(tài)庫(kù)時(shí), 需要額外修改/etc/ld.so.conf或者在/etc/ld.so.conf.d目錄下創(chuàng)建包含對(duì)應(yīng)目錄的.conf文件, 而后執(zhí)行ldconfig
  10. 至此protobuf就算是安裝完成啦, 使用protoc --version再檢查一下試試

如果上述安裝步驟中遇到權(quán)限問(wèn)題, 那么可以使用sudo命令, 或者切成root(慎用root 哈哈哈)


三 簡(jiǎn)單示例

編寫(xiě)簡(jiǎn)單的proto文件


// test.proto

syntax = "proto3";

package lm;

message helloworld

{

    int32 id = 1;

    string name = 2;

    repeated string hero = 3;                                                                     

}

protoc編譯


protoc -I=./ --cpp_out=./ ./test.proto

  • 其中 -I后接import的根目錄, --cpp_out生成文件的目錄, 最后一個(gè)參數(shù)表示待編譯的文件

  • 編譯后將會(huì)生成一個(gè).pb.cc文件和一個(gè).pb.h文件

使用示例


#include <iostream>

#include <fstream>

#include "test.pb.h"

int main()

{

    lm::helloworld ob1, ob2;

    ob1.set_id(1);

    ob1.set_name("szw");

    ob1.add_hero("loong");

    ob1.add_hero("uk");

    printf("ob1\n");

    ob1.PrintDebugString();

    std::ofstream fout("test.txt");

    if (!ob1.SerializeToOstream(&fout)){

        perror("ob1 SerializeToOstream Wrong!\n");

        exit(-1);

    }

    fout.close();

    std::ifstream fin("test.txt");

    if(!ob2.ParseFromIstream(&fin)){

        perror("ob2 ParseFromIstream Wrong!\n");

        exit(-1);

    }

    fin.close();

    printf("ob2\n");

    ob2.PrintDebugString();

    return 0;

}

makefile


all:

 g++ -std=c++11 -c -o test.o test.cpp

 g++ -std=c++11 -c -o test.pb.o test.pb.cc

 g++ -std=c++11 -o test test.o test.pb.o -lprotobuf -lpthread

clean:

 rm -rf *.o

執(zhí)行結(jié)果


ob1

id: 1

name: "szw"

hero: "loong"

hero: "uk"

ob2

id: 1

name: "szw"

hero: "loong"

hero: "uk"

最后編輯于
?著作權(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ù)。

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