Protobuf的簡單介紹、使用和分析

来源:http://www.cnblogs.com/huoqm/archive/2017/11/17/7850192.html
-Advertisement-
Play Games

Protobuf的簡單介紹、使用和分析 一、protobuf是什麼? protobuf(Google Protocol Buffers)是Google提供一個具有高效的協議數據交換格式工具庫(類似Json),但相比於Json,Protobuf有更高的轉化效率,時間效率和空間效率都是JSON的3-5倍 ...


 

 

Protobuf的簡單介紹、使用和分析

 

一、protobuf是什麼?

        protobuf(Google Protocol Buffers)是Google提供一個具有高效的協議數據交換格式工具庫(類似Json),但相比於Json,Protobuf有更高的轉化效率,時間效率和空間效率都是JSON的3-5倍。後面將會有簡單的demo對於這兩種格式的數據轉化效率的對比。但這個庫目前使用還不是太流行,據說谷歌內部很多產品都有使用。

 

二、protobuf有什麼?

        Protobuf 提供了C++、java、python語言的支持,提供了windows(proto.exe)和linux平臺動態編譯生成proto文件對應的源文件。proto文件定義了協議數據中的實體結構(message ,field)

關鍵字message: 代表了實體結構,由多個消息欄位(field)組成。

消息欄位(field): 包括數據類型、欄位名、欄位規則、欄位唯一標識、預設值

數據類型:常見的原子類型都支持(在FieldDescriptor::kTypeToName中有定義)

欄位規則:(在FieldDescriptor::kLabelToName中定義)

        required:必須初始化欄位,如果沒有賦值,在數據序列化時會拋出異常

        optional:可選欄位,可以不必初始化。

        repeated:數據可以重覆(相當於java 中的Array或List)

        欄位唯一標識:序列化和反序列化將會使用到。

預設值:在定義消息欄位時可以給出預設值。

 

三、protobuf有什麼用?

        Xml、Json是目前常用的數據交換格式,它們直接使用欄位名稱維護序列化後類實例中欄位與數據之間的映射關係,一般用字元串的形式保存在序列化後的位元組流中。消息和消息的定義相對獨立,可讀性較好。但序列化後的數據位元組很大,序列化和反序列化的時間較長,數據傳輸效率不高。

        Protobuf和Xml、Json序列化的方式不同,採用了二進位位元組的序列化方式,用欄位索引和欄位類型通過演算法計算得到欄位之前的關係映射,從而達到更高的時間效率和空間效率,特別適合對數據大小和傳輸速率比較敏感的場合使用。

四、Protobuf在Android上的使用

1、創建proto文件,定義消息的實體結構

2、編譯proto文件生成對應的java文件

3、添加protobuf-java-2.5.0.jar到android工程

4、在android中實現對消息結構的序列化/反序列化  

 

五、Protobuf與json的對比

1、創建product.proto文件

        定義了三個Message(ProductInfo、PhoneInfo、Watch)消息結構

2、消息結構對應的java類(ProductInfo、PhoneInfo、Watch)

 

3、消息結構和java對象賦值

PhoneName:” idol3”

Price:2000

Top:1

 

WatchName:” tcl watch”

Price:1000

Top:1

 

4、JSON字元串

 

{"phone":{"phoneName":"idol3","price":2000,"top":1},"watch":{"watchName":"tcl wtch","top":1,"price":1000}}

 

5、Protobuf轉化後的二進位文件

 

空間效率

Json:107個位元組

Protobuf:32個位元組

 

時間效率

Json序列化: 1ms ,  反序列化:0ms

Protobuf 序列化: 0ms 反序列化:0ms

 

將public List<Phone> list和repeated PhoneInfo phoneInfoList =3;都賦值為1000個PhoneInfo

 

空間效率

Json:4206個位元組

Protobuf:1332個位元組

 

時間效率

Json序列化: 4ms ,  反序列化:1ms

Protobuf 序列化: 1ms 反序列化:0ms

六、protobuf的簡單分析

1、優缺點

優點:通過以上的時間效率和空間效率,可以看出protobuf的空間效率是JSON的2-5倍,時間效率要高,對於數據大小敏感,傳輸效率高的模塊可以採用protobuf庫

 

缺點:消息結構可讀性不高,序列化後的位元組序列為二進位序列不能簡單的分析有效性;目前使用不廣泛,只支持java,C++和Python;

 

2、數據序列化/反序列化

a、規則:

protobuf把消息結果message也是通過 key-value對來表示。只是其中的key是採取一定的演算法計算出來的即通過每個message中每個欄位(field index)和欄位的數據類型進行運算得來的key = (index<<3)|type;

type類型的對應關係如下:

 

Type

Meaning

Used For

0

Varint

int32, int64, uint32, uint64, sint32, sint64, bool, enum

1

64-bit

fixed64, sfixed64, double

2

Length-delimited

string, bytes, embedded messages, packed repeated fields

3

Start group

groups (deprecated)

4

End group

groups (deprecated)

5

32-bit

fixed32, sfixed32, float

 

Value會根據數據類型的不同會有兩種表現形式:

對於各種int,bool,enum類型,value就是Varint

對於string,bytes,message等等類型,value就是length+原始內容編碼

 

Varints是一種緊湊表示數字的方法。它用一個或者多個位元組表示一個數字,值越小的數字位元組數越少。相對於傳統的用4位元組表示int32類型數字,Varints對於小於128的數值都可以用一個位元組表示,大於128的數值會用更多的位元組來表示,對於很大的數據則需要用5個位元組來表示。

 

Varints演算法描述: 每一個位元組的最高位都是有特殊含義的,如果是1,則表示後續的位元組也是該數字的一部分;如果是0,則結束

b、demo生成的的二進位文件反序列化。

第1個位元組 (0A)

欄位索引(index):         0A = 0001010  0A>>3 = 001 = 1

數據類型(type):           0A = 0001010&111  = 2 (String);

 

第2個位元組 (0C)

字元串長度(length):      0E = 12;

字元串:                         0A 05 69 64 6F 6C 33 10 01 18 BD 0F

 

第3個位元組 (0A)

因為字元串是來自phoneInfo屬於嵌套類型

欄位索引(index):         0A = 0001010  0A>>3 = 001 = 1

數據類型(type):           0A = 0001010&111  = 2 (String);


第4-9個位元組(69 64 6F 6C 33)

字元串長度(length):    05 = 5

字元串:                       69 64 6F 6C 33 = idol3

 

第10個位元組 (10)

欄位索引(index):         10 = 00010000    10A>>3 = 0010 = 2

數據類型(type):           10 = 00010000&111  = 0 (Varints);

 

第11個位元組  (01)

Varints:                          01 = 00001位元組的最高位為0 整數結束

Value:                            1;

 

第12個位元組(18)

欄位索引(index):           18 = 00011000    18>> 00011 = 3

數據類型(type):           18 = 00011000&111  = 0 (Varints);

 

第13個位元組(D0)

最高位為1,整數計算到下一個位元組

 

第14個位元組(0F)

最高位為0,整數計算結束

Value:為11111010000 =2000

 

C、反序列化結果

phoneinfo為

phoneName = “idol3”

top = 1

price = 2000;

 

同樣的方法watchInfo為:

watchName = “tcl name”

top = 1

price=2000 

3、時間效率

通過protobuf序列化/反序列化的過程可以得出:protobuf是通過演算法生成二進位流,序列化與反序列化不需要解析相應的節點屬性和多餘的描述信息,所以序列化和反序列化時間效率較高。

4、空間效率

xml、json是用欄位名稱來確定類實例中欄位之間的獨立性,所以序列化後的數據多了很多描述信息,增加了序列化後的位元組序列的容量。

 

Protobuf的序列化/反序列化過程可以得出:

protobuf是由欄位索引(fieldIndex)與數據類型(type)計算(fieldIndex<<3|type)得出的key維護欄位之間的映射且只占一個位元組,所以相比json與xml文件,protobuf的序列化位元組沒有過多的key與描述符信息,所以占用空間要小很多。

七、Protobuf的源碼分析

1、protobuf在java使用的序列化流程

 

java程式調用parserFrom(byte[] data)開始位元組序列的反序列,Java程式通過調用編譯生類GenerateMessage中的wirteTo()方法開始將序列化後的位元組寫入輸出流中

 

GenerateMessage 繼承AbstractMessage類,序列化最終在AbstractMesssage中完成,序列化的實現過程:

a、遍歷對象中Message結構()

調用AbstractMessage類中的writeTo()方法

 

b、 序列化Message中每一個欄位

調用CodeOutputStream類中的writeMessageSetExtension()方法

 

c、 對於Varints  Tag 的序列化流程:

調用CodeOutputStream類中的writeUInt32()方法

調用CodeOutputStream類中的WriteRawVarint32()方法

 

d、 對於非Varints Tag的序列化

調用CodeOutputStream類中的WriteTag()方法

 

 

具體的序列化實現都在CodedOutputStream中完成

 

2、java使用protobuf 的反序列化流程分析

java程式通過調用parserFrom(byte[] data)開始反序列化

 

具體在com.google.protobuf. AbstractParser類中實現

 

 

 

 

 

最後在com.google.protobuf.CodedInputStream類中完成反序列化

3、動態編譯

以windows下用protoc.exe工具實現proto文件編譯為例,protoc.exe是用C++實現。在控制台執行命令:

編譯的流程:

檢查proto的語法規則

將proto的文件中的message結構轉換為GenerateMessage類的子類,並實現Builder介面。

編譯流程

Main.cc中的main()方法

 

Command_line_interface.cc中的Run()方法

 

Import類中Import()

 

在Descriptor中完成message消息的收集和轉化。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先還是xml的配置文件 接著是假定dao的類 生成一個對象很方便,甚至@Component(value="dao")中的value=都可以不寫,變成 @Component("dao") 然後是假定service的類 與配置文件中使用<bean id="service" class="com.swi ...
  • 其實這個就相當於模擬人的點擊事件來連續的訪問瀏覽器。如果你玩過王者榮耀的話在2016年一月份的版本裡面就有一個bug。 安卓手機下載一個按鍵精靈就可以在冒險模式裡面設置按鍵,讓手機自動玩闖關,一局19個金幣,一晚上就一個英雄了。不過 程式員也不是吃素的。給一個星期設置了大概4000金幣上限。有興趣的 ...
  • solr索引庫的創建 一、找到你安裝的【solrhome】目錄(我的是這個) 二、進入該目錄 三、選擇其中任意一個索引庫複製一份到該目錄下並更名為要創建的索引庫名稱 四、進入【myindex】目錄下,該目錄下會有2個目錄1個配置文件 五、刪除【data】目錄和【core.properties】配置文 ...
  • 經常碰到中文亂碼問題,web,xml 配置過,前端配置過一般都能解決問題。 另外還有一種 ,tomcat的配置 加入 ...
  • 轉眼已經出來實習4個多月了,目前感覺這個公司在技術上是我喜歡的類型,技術氛圍很好,並且當前公司所做產品所使用技術都是像當前大公司靠攏。並且我的師傅技術真是十分扎實,不僅僅是應用知識高超,同時對基礎知識細節的理解也是很深的,在我的學習過程中,起到了很大的幫助。 再說點廢話吧,老大和我師傅他們對待技術真 ...
  • 架構 grafana和prometheus之前安裝配置過,見: "Grafana+Prometheus打造全方位立體監控系統" MySql安裝 MySql的地位和重要性就不言而喻了,作為開源產品深受廣大中小企業以及互聯網企業喜愛,所以這裡我們也有必要對其進行相應的監控。 由於最近更換了CentOS7 ...
  • 前臺: 支持四套模版, 可以在後臺切換 系統介紹: 1.網站後臺採用主流的 SSM 框架 jsp JSTL,網站後臺採用freemaker靜態化模版引擎生成html 2.因為是生成的html,所以訪問速度快,輕便,對伺服器負擔小 3.網站前端採用主流的響應式佈局,同一頁面同時支持PC、平板、手機(三 ...
  • rabbitmq里有一些概念我們要清楚,如vhost,channel,exchange,queue等,而前段時間在部署rabbitmq環境時啟用了虛擬主機vhost,感覺他主要是起到了消息隔離的作用,下麵分別再說一下它們的知識。 VHost vhost去做第一層的區分,虛擬主機,工作組等,它預設是/ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...