【快速上手ProtoBuf】基本使用

文章目錄

  • 1 :peach:初識 ProtoBuf:peach:
    • 1.1 :apple:序列化概念:apple:
    • 1.2 :apple:ProtoBuf 是什么:apple:
    • 1.3 :apple:ProtoBuf 的使用特點:apple:
  • 2 :peach:創建 .proto ?件:peach:
  • 3 :peach:編譯 .proto 文件:peach:
  • 3 :peach:序列化與反序列化的使用:peach:


1 🍑初識 ProtoBuf🍑

1.1 🍎序列化概念🍎

序列化和反序列化

  • 序列化:把對象轉換為字節序列的過程稱為對象的序列化。
  • 反序列化:把字節序列恢復為對象的過程稱為對象的反序列化。

什么情況下需要序列化

  • 存儲數據:當你想把的內存中的對象狀態保存到?個?件中或者存到數據庫中進行持久化時。
  • ?絡傳輸:?絡直接傳輸數據,但是?法直接傳輸對象,所以要在傳輸前序列化,傳輸完成后反序列化成對象。例如我們之前學習過 socket 編程中發送與接收數據。

如何實現序列化

常見的有xmlymljsonprotobuf

1.2 🍎ProtoBuf 是什么🍎

我們先來看看官?給出的答案是什么?

  • Protocol Buffers 是 Google 的?種語??關、平臺?關、可擴展的序列化結構數據的?法,它可?于(數據)通信協議、數據存儲等。
  • Protocol Buffers 類?于 XML,是?種靈活,?效,?動化機制的結構數據序列化?法,但是?XML 更?、更快、更為簡單。
  • 你可以定義數據的結構,然后使?特殊?成的源代碼輕松的在各種數據流中使?各種語?進?編寫和讀取結構數據。你甚?可以更新數據結構,?不破壞由舊數據結構編譯的已部署程序。

簡單來講, ProtoBuf(全稱為 Protocol Buffer)是讓結構數據序列化的?法,其具有以下特點:

  • 語??關、平臺?關:即 ProtoBuf ?持 Java、C++、Python 等多種語?,?持多個平臺。
  • ?效:即? XML 更?、更快、更為簡單。
  • 擴展性、兼容性好:你可以更新數據結構,?不影響和破壞原有的舊程序。

1.3 🍎ProtoBuf 的使用特點🍎

在這里插入圖片描述

  1. 編寫 .proto ?件,?的是為了定義結構對象(message)及屬性內容。
  2. 使? protoc 編譯器編譯 .proto ?件,?成?系列接?代碼,存放在新?成頭?件和源?件中。
  3. 依賴?成的接?,將編譯?成的頭?件包含進我們的代碼中,實現對 .proto ?件中定義的字段進?設置和獲取,和對 message 對象進?序列化和反序列化。

總的來說:ProtoBuf 是需要依賴通過編譯?成的頭?件和源?件來使?的。


2 🍑創建 .proto ?件🍑

?件規范

  • 創建 .proto ?件時,?件命名應該使?全?寫字?命名,多個字?之間? _ 連接。比如:lower_snake_case.proto
  • 書寫 .proto ?件代碼時,應使? 2 個空格的縮進。

指定 proto3 語法

Protocol Buffers 語?版本3,簡稱 proto3,是 .proto ?件最新的語法版本。proto3 簡化了 ProtocolBuffers 語?,既易于使?,?可以在更?泛的編程語?中使?。它允許你使? Java,C++,Python等多種語??成 protocol buffer 代碼。

.proto ?件中,要使? syntax = "proto3"; 來指定?件語法為 proto3,并且必須寫在除去注釋內容的第??。 如果沒有指定,編譯器會使?proto2語法。

package 聲明符

package 是?個可選的聲明符,能表? .proto ?件的命名空間,在項?中要有唯?性。它的作?是為了避免我們定義的消息出現沖突。(類似于C++中的namespace)
比如我們就可以像這么寫:

syntax = "proto3";
package contacts;

定義消息(message)

消息(message): 要定義的結構化對象,我們可以給這個結構化對象中定義其對應的屬性內容。
這?再提?下為什么要定義消息?在?絡傳輸中,我們需要為傳輸雙?定制協議。定制協議說?了就是定義結構體或者結構化數據,?如,tcp,udp 報?就是結構化的。再?如將數據持久化存儲到數據庫時,會將?系列元數據統??對象組織起來,再進?存儲。

消息類型命名規范:使?駝峰命名法,?字??寫。

定義消息字段

在 message 中我們可以定義其屬性字段,字段定義格式為:字段類型 字段名 = 字段唯?編號

  • 字段名稱命名規范:全小寫字?,多個字?之間? _ 連接。
  • 字段類型分為:標量數據類型 和 特殊類型(包括枚舉、其他消息類型等)。
  • 字段唯?編號:?來標識字段,?旦開始使?就不能夠再改變。

該表格展?了定義于消息體中的標量數據類型,以及編譯 .proto ?件之后?動?成的類中與之對應的字段類型。在這?展?了與 C++ 語?對應的類型:

.proto TypeNotesC++ Type
doubledouble
floatfloat
int32使?變?編碼[1]。負數的編碼效率較低?若字段可能為負值,應使? sint32 代替int32
int64使?變?編碼[1]。負數的編碼效率較低?若字段可能為負值,應使? sint34 代替int64
uint32使?變?編碼[1]。uint32
uint64使?變?編碼[1]。uint64
sint32使?變?編碼[1]。符號整型。負值的編碼效率?于常規的 int32 類型int32
sin64使?變?編碼[1]。符號整型。負值的編碼效率?于常規的 int64 類型int64
fixed32定? 4 字節。若值常?于228 則會? uint32 更?效uint32
fixed64定? 8 字節。若值常?于228 則會? uint32 更?效uint64
sfixed32定? 4 字節int32
sfixed64定? 8 字節int64
boolbool
string包含 UTF-8 和 ASCII 編碼的字符串,?度不能超過232string
bytes可包含任意的字節序列但?度不能超過 232string

[1] 變?編碼是指:經過protobuf 編碼后,原本4字節或8字節的數可能會被變為其他字節數。

此時我們就可以這樣寫:

syntax = "proto3";
package contacts;
message PeopleInfo 
{string name = 1; int32 age = 2; 
}

在這?還要特別講解?下字段唯?編號

1 ~ 536,870,911 (229 - 1) ,其中 19000 ~ 19999 不可?。

9000 ~ 19999 不可?是因為:在 Protobuf 協議的實現中,對這些數進?了預留。如果?要在.proto?件中使?這些預留標識號,例如將 name 字段的編號設置為19000,編譯時就會報警。

值得?提的是,范圍為 1 ~ 15 的字段編號需要?個字節進?編碼, 16 ~ 2047 內的數字需要兩個字節進?編碼。編碼后的字節不僅只包含了編號,還包含了字段類型。所以 1 ~ 15 要?來標記出現?常頻繁的字段,要為將來有可能添加的、頻繁出現的字段預留?些出來。


3 🍑編譯 .proto 文件🍑

編譯命令?格式為:

protoc [--proto_path=IMPORT_PATH] --cpp_out=DST_DIR path/to/file.proto
  • protoc 是 Protocol Buffer 提供的命令?編譯?具。
  • --proto_path 指定 被編譯的.proto?件所在?錄,可多次指定。可簡寫成 -I IMPORT_PATH 如不指定該參數,則在當前目錄進行搜索。當某個.proto ?件 import 其他.proto ?件時,或需要編譯的 .proto ?件不在當前?錄下,這時就要?-I來指定搜索?錄。
  • --cpp_out= 指編譯后的?件為 C++ ?件。.表示當前路徑。
  • OUT_DIR 編譯后?成?件的?標路徑。
  • path/to/file.proto 要編譯的.proto?件。

當我們編譯成功后就會生成兩個文件,一個頭文件,一個源文件:
在這里插入圖片描述

對于編譯?成的 C++ 代碼:

  • 對于每個 message ,都會?成?個對應的消息類。
  • 在消息類中,編譯器為每個字段提供了獲取和設置?法,以及?下其他能夠操作字段的?法。
  • 編輯器會針對于每個 .proto ?件?成 .h .cc ?件,分別?來存放類的聲明與類的實現。

我們在VSCode下觀察 .h文件:在這里插入圖片描述提示:有時候在查看時會出現大量飄紅現象,這是由于插件的原因,本身是沒有錯誤的。

  • 每個字段都有設置和獲取的?法, get 的名稱與?寫字段完全相同,set ?法以 set_ 開頭。
  • 每個字段都有?個 clear_ ?法,可以將字段重新設置回 empty 狀態。

除此之外包括序列化?法和反序列化?法,這里列舉小部分供參考:

class MessageLite 
{
public://序列化:bool SerializeToOstream(ostream* output) const; // 將序列化后數據寫??件流bool SerializeToArray(void *data, int size) const;bool SerializeToString(string* output) const;//反序列化:bool ParseFromIstream(istream* input); // 從流中讀取數據,再進?反序列化動作bool ParseFromArray(const void* data, int size);bool ParseFromString(const string& data);
};

注意:

  • 序列化的結果為?進制字節序列,???本格式。
  • 以上三種序列化的?法沒有本質上的區別,只是序列化后輸出的格式不同,可以供不同的應?場景使?。
  • 序列化的 API 函數均為const成員函數,因為序列化不會改變類對象的內容, ?是將序列化的結果保存到函數?參指定的地址中。

查看更加詳細的API點擊這里:【API】


3 🍑序列化與反序列化的使用🍑

創建?個測試?件 main.cc,?法中我們實現:

  • 對?個聯系?的信息使? PB 進?序列化,并將結果打印出來。
  • 對序列化后的內容使? PB 進?反序列,解析出聯系?信息并打印出來。

參考代碼:

#include <iostream>
#include "contacts.pb.h" // 引?編譯?成的頭?件
using namespace std;int main()
{string people_str;{contacts::PeopleInfo people;people.set_age(21);people.set_name("蝦頭男");// 調?序列化?法,將序列化后的?進制序列存?string中if (!people.SerializeToString(&people_str)){cout << "序列化聯系?失敗." << endl;}// 打印序列化結果cout << "序列化后的 people_str: " << people_str << endl;}{contacts::PeopleInfo people;// 調?反序列化?法,讀取string中存放的?進制序列,并反序列化出對象if (!people.ParseFromString(people_str)){cout << "反序列化出聯系?失敗." << endl;}// 打印結果cout << "Parse age: " << people.age() << endl;cout << "Parse name: " << people.name() << endl;}
}

makefile:

test:main.ccg++ -o $@ $^ contacts.pb.cc -std=c++11 -lprotobuf
.PHONY:clean
clean:rm -r test

執行:
在這里插入圖片描述
我們發現報了一個錯誤,原因是系統找不到共享庫,我們執行下面命令即可:

sudo vim /etc/ld.so.conf
#添加以下路徑
/usr/local/lib

修改/etc/ld.so.conf需要root權限。
然后執行:

sudo ldconfig

我們重新編譯生成:
在這里插入圖片描述
發現符合預期結果。由于序列化的結果是二進制,所以有些內容沒有打印出來亂碼很正常。
所以相對于 xmlJSON 來說,因為被編碼成?進制,破解成本增?,ProtoBuf 編碼是相對安全的。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715791.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715791.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715791.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

洛谷 2036.PERKET

采用遞歸法的方式進行題解。 思路&#xff1a;首先我們知道在n種材料當中&#xff0c;我們需要從中選擇至少有一種得配料才行。也就是說&#xff0c;我們選擇的配料數目是自己決定的&#xff0c;而不是那種組合型得對于你有要求的組合型遞歸方式。 所以我們會想到用指數型得遞…

(五)網絡優化與超參數選擇--九五小龐

網絡容量 網絡中神經單元數越多&#xff0c;層數越多&#xff0c;神經網路的擬合能力越強。但是訓練速度&#xff0c;難度越大&#xff0c;越容易產生過擬合。 如何選擇超參數 所謂超參數&#xff0c;也就是搭建神經網路中&#xff0c;需要我們自己去選擇&#xff08;不是通…

LeetCode 刷題 [C++] 第45題.跳躍游戲 II

題目描述 給定一個長度為 n 的 0 索引整數數組 nums。初始位置為 nums[0]。 每個元素 nums[i] 表示從索引 i 向前跳轉的最大長度。換句話說&#xff0c;如果你在 nums[i] 處&#xff0c;你可以跳轉到任意 nums[i j] 處: 0 < j < nums[i]i j < n 返回到達 nums[n …

遞歸函數(c++題解)

題目描述 對于一個遞歸函數w(a, b, c)。 如果a < 0 or b < 0 or c < 0就返回值1。 如果a > 20 or b > 20 or c > 20就返回W(20,20,20)。 如果a < b并且b < c 就返回w(a, b, c ? 1) w(a, b ? 1, c ? 1) ? w(a, b ? 1, c)&#xff0c; 其它別…

計算機網絡知多少-第1篇

一、 從輸入URL到頁面展示到底發生了什么&#xff1f; 1. 首先瀏覽器會查看電腦本地緩存&#xff0c;如果有直接返回&#xff0c;否則需要進行下一步的網絡請求。 2. 在網絡請求之前&#xff0c;需要先進行DNS解析&#xff0c;來找到請求域名的ip地址。如果是HTTPS請求&#…

【C語言】熟悉文件基礎知識

歡迎關注個人主頁&#xff1a;逸狼 創造不易&#xff0c;可以點點贊嗎~ 如有錯誤&#xff0c;歡迎指出~ 文件 為了數據持久化保存&#xff0c;使用文件&#xff0c;否則數據存儲在內存中&#xff0c;程序退出&#xff0c;內存回收&#xff0c;數據就會丟失。 程序設計中&…

微信小程序,h5端自適應登陸方式

微信小程序端只顯示登陸(獲取opid),h5端顯示通過賬戶密碼登陸 例如: 通過下面的變量控制: const isWeixin ref(false); // #ifdef MP-WEIXIN isWeixin.value true; // #endif

Git 查看提交歷史

命令說明git log查看歷史提交記錄git blame (file)以列表形式查看指定文件的歷史修改記錄 git log 在使用 Git 提交了若干更新之后&#xff0c;又或者克隆了某個項目&#xff0c;想回顧下提交歷史&#xff0c;我們可以使用 git log 命令查看。 git log 命令用于查看 Git 倉庫中…

LIN基礎:從LIN Frame開始

目錄&#xff1a; 1、LIN的網絡拓撲 2、LIN Frame 1&#xff09;Header 2&#xff09;Response 3、LIN的通信規則 1&#xff09;LIN的發送行為示例 2&#xff09;LIN的接收行為示例 雖然LIN總線的通信速率不高&#xff0c;工程中&#xff0c;最高的速率也就19200bps。…

c語言extern關鍵字

extern 是C和C中的關鍵字&#xff0c;用于聲明一個變量或函數的存在&#xff0c;但不進行定義。 它通常用于在一個源文件中引用另一個源文件中定義的變量或函數。 例如&#xff0c;extern int x; 表示 x 是一個整數變量&#xff0c;但它的實際定義將在其他文件中。在引用它的文…

StarRocks——Stream Load 事務接口實現原理

目錄 前言 一、StarRocks 數據導入 二、StarRocks 事務寫入原理 三、InLong 實時寫入StarRocks原理 3.1 InLong概述 3.2 基本原理 3.3 詳細流程 3.3.1 任務寫入數據 3.3.2 任務保存檢查點 3.3.3 任務如何確認保存點成功 3.3.4 任務如何初始化 3.4 Exactly Once 保證…

Leetcode - 周賽386

目錄 一&#xff0c;3046. 分割數組 二&#xff0c;3047. 求交集區域內的最大正方形面積 三&#xff0c;3048. 標記所有下標的最早秒數 I 四&#xff0c;3049. 標記所有下標的最早秒數 II 一&#xff0c;3046. 分割數組 將題目給的數組nums分成兩個數組&#xff0c;且這兩個…

探索RedisJSON:將JSON數據力量帶入Redis世界

探索RedisJSON&#xff1a;將JSON數據力量帶入Redis世界 當我們談論數據存儲和查詢時&#xff0c;Redis和JSON都是無法忽視的重要角色。Redis以其高效的鍵值存儲、快速的讀/寫速度、以及豐富的數據結構贏得了開發者的喜愛。而JSON&#xff0c;作為一種輕量級的數據交換格式&am…

「Vue3系列」Vue3 條件語句/循環語句

文章目錄 一、Vue3 條件語句1. v-if2. v-else-if 和 v-else3. v-show4. 使用計算屬性進行條件渲染5. v-if與v-show比較v-ifv-show性能考慮使用場景 二、Vue3 循環語句1. 遍歷數組2. 遍歷對象3. 使用索引4. 注意事項 三、相關鏈接 一、Vue3 條件語句 在 Vue 3 中&#xff0c;你…

盲人出行:科技創造美好的未來

在繁忙的都市中&#xff0c;我每天都要面對許多挑戰&#xff0c;盲人出行安全保障一直難以得到落實。我看不見這個世界&#xff0c;只能依靠觸覺和聽覺來感知周圍的一切。然而&#xff0c;我從未放棄過對生活的熱愛和對未來的憧憬。在一次機緣巧合下&#xff0c;我認識了一款名…

C3_W2_Collaborative_RecSys_Assignment_吳恩達_中英_Pytorch

Practice lab: Collaborative Filtering Recommender Systems(實踐實驗室:協同過濾推薦系統) In this exercise, you will implement collaborative filtering to build a recommender system for movies. 在本次實驗中&#xff0c;你將實現協同過濾來構建一個電影推薦系統。 …

VLAN實驗報告

實驗要求&#xff1a; 實驗參考圖&#xff1a; 實驗過程&#xff1a; r1: [r1]int g 0/0/0.1 [r1-GigabitEthernet0/0/0.1]ip address 192.168.1.1 24 [r1-GigabitEthernet0/0/0.1]dot1q termination vid 2 [r1-GigabitEthernet0/0/0.1]arp broadcast enable [r1]int g 0/0/…

Mysql學習之MVCC解決讀寫問題

多版本并發控制 什么是MVCC MVCC &#xff08;Multiversion Concurrency Control&#xff09;多版本并發控制。顧名思義&#xff0c;MVCC是通過數據行的多個版本管理來實現數據庫的并發控制。這項技術使得在InnoDB的事務隔離級別下執行一致性讀操作有了保證。換言之&#xff0…

django的模板渲染中的【高級定制】:按數據下標id來提取數據

需求&#xff1a; 1&#xff1a;在一個頁面中顯示一張數據表的數據 2&#xff1a;不能使用遍歷的方式 3&#xff1a;頁面中的數據允許通過admin后臺來進行修改 4&#xff1a;把一張數據表的某些內容渲染到[xxx.html]頁面 5&#xff1a;如公司的新商品頁面&#xff0c;已有固定的…

《夢幻西游》本人收集的34個單機版游戲,有詳細的視頻架設教程,值得收藏

夢幻西游這款游戲&#xff0c;很多人玩&#xff0c;喜歡研究的趕快下載吧。精心收集的34個版本。不容易啊。里面有詳細的視頻架設教程&#xff0c;可以外網呢。 《夢幻西游》本人收集的34個單機版游戲&#xff0c;有詳細的視頻架設教程&#xff0c;值得收藏 下載地址&#xff1…