protobuf 序列化和反序列化操作流程
前言
Protocol Buffers(protobuf)是一種輕量級(jí)的數(shù)據(jù)交換格式,可以用于結(jié)構(gòu)化數(shù)據(jù)的序列化和反序列化。它使用二進(jìn)制格式來(lái)編碼數(shù)據(jù),以提高傳輸效率和數(shù)據(jù)壓縮比。
在protobuf中,我們可以使用.proto文件來(lái)定義消息類型,并使用編譯器生成針對(duì)各種編程語(yǔ)言的序列化和反序列化代碼。序列化是將結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)換為一系列字節(jié)的過(guò)程,反序列化則是將字節(jié)流解析為結(jié)構(gòu)化數(shù)據(jù)的過(guò)程。
序列化的過(guò)程通常涉及以下步驟:
定義消息類型:使用.proto文件定義消息類型和字段。
編寫應(yīng)用程序:編寫應(yīng)用程序,創(chuàng)建消息對(duì)象并填充字段。
序列化數(shù)據(jù):使用protobuf庫(kù),將消息對(duì)象序列化為字節(jié)數(shù)組。
傳輸數(shù)據(jù):將字節(jié)數(shù)組發(fā)送給接收方。
反序列化數(shù)據(jù):接收方使用protobuf庫(kù),將字節(jié)數(shù)組反序列化為消息對(duì)象,并訪問(wèn)其中的字段。
在序列化過(guò)程中,protobuf使用壓縮技術(shù)來(lái)減小數(shù)據(jù)的大小,從而提高傳輸效率。此外,protobuf支持向前和向后兼容的特性,可以使得我們?cè)诟孪㈩愋蜁r(shí),不會(huì)破壞現(xiàn)有的序列化數(shù)據(jù)
1. 序列化
序列化 (Serialization)將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问降倪^(guò)程,與之相對(duì)應(yīng)的過(guò)程稱之為反序列化(Unserialization)。序列化和反序列化主要用于解決在跨平臺(tái)和跨語(yǔ)言的情況下, 模塊之間的交互和調(diào)用,但其本質(zhì)是為了解決數(shù)據(jù)傳輸問(wèn)題。
實(shí)現(xiàn)數(shù)據(jù)序列化:
- 要有原始數(shù)據(jù)
- 復(fù)合類型 -> 最常見的情況
- 基礎(chǔ)數(shù)據(jù)類型
- 通過(guò)某些方式 -> 另外一種形式的數(shù)據(jù)
- 得到的數(shù)據(jù)干啥? -> 目的: 進(jìn)行分發(fā), 分發(fā)到不同的終端/平臺(tái), 保證不同的平臺(tái)能正確解析
- 網(wǎng)絡(luò)傳輸
- 磁盤拷貝
- 序列化目的不是為了加密, 為的是數(shù)據(jù)的跨平臺(tái)傳輸
- 序列化的整體過(guò)程:
- 發(fā)送端
- 原始數(shù)據(jù) -> 序列化 (編碼) -> 特殊格式的字符串
- 發(fā)送這個(gè)字符串
- 接收端:
- 接收數(shù)據(jù)
- 特殊格式的字符串 -> 反序列化 (解碼) -> 原始數(shù)據(jù)
- 對(duì)原始數(shù)據(jù)進(jìn)行處理
1.1 網(wǎng)絡(luò)通信中的問(wèn)題分析
發(fā)送過(guò)程中遇到的一些問(wèn)題?
- 平臺(tái)不同
- 如果不是字符串, 需要進(jìn)行字節(jié)序轉(zhuǎn)換
- 語(yǔ)言不同
- 字節(jié)對(duì)齊問(wèn)題
1.2 常用的序列化方式
XML( Extensible Markup Language )類似于html
XML是一種常用的序列化和反序列化協(xié)議,具有跨機(jī)器,跨語(yǔ)言等優(yōu)點(diǎn)。XML歷史悠久,其1.0版本早在1998年就形成標(biāo)準(zhǔn),并被廣泛使用至今。
XML的最初產(chǎn)生目標(biāo)是對(duì)互聯(lián)網(wǎng)文檔進(jìn)行標(biāo)記,所以它的設(shè)計(jì)理念中就包含了對(duì)于人和機(jī)器都具備可讀性。 但是,當(dāng)這種標(biāo)記文檔的設(shè)計(jì)被用來(lái)序列化對(duì)象的時(shí)候,就顯得冗長(zhǎng)而復(fù)雜。
XML基本格式:
<?xml version="1.0" encoding="utf-8"?> <Library> <Type name="小說(shuō)"> <Book author="J.K.ROWLING" price="12$">哈利波特1</Book> <Book author="J.K.ROWLING" price="12$">哈利波特2</Book> <Book author="J.K.ROWLING" price="12$">哈利波特3</Book> <Book author="J.K.ROWLING" price="12$">哈利波特4</Book> </Type> <Type name="歷史"> <Book author="司馬遷" price="20$">史記</Book> </Type> </Library>
Json( JavaScript Object Notation )
JSON起源于弱類型語(yǔ)言Javascript,它的產(chǎn)生來(lái)自于一種稱之為"關(guān)聯(lián)數(shù)組(Associative array)"的概念,其本質(zhì)是就是采用"鍵值對(duì)"的方式來(lái)描述對(duì)象。
JSON格式保持了XML的人眼可讀的優(yōu)點(diǎn),非常符合工程師對(duì)對(duì)象的理解。
相對(duì)于XML而言,序列化后的數(shù)據(jù)更加簡(jiǎn)潔(XML所產(chǎn)生序列化之后文件的大小接近JSON的兩倍),而且其協(xié)議比較簡(jiǎn)單,解析速度比較快。
JSON格式具備Javascript的先天性支持,所以被廣泛應(yīng)用于Web browser的應(yīng)用常景中,是Ajax的事實(shí)標(biāo)準(zhǔn)協(xié)議。
// json是一種數(shù)據(jù)格式, 不是語(yǔ)言, 和平臺(tái)語(yǔ)言無(wú)關(guān) // json數(shù)組 [整形, 浮點(diǎn)型, 布爾類型, 字符串, json數(shù)組, json對(duì)象] [12, 12.44, true, "hello", [1,2,3]] // json對(duì)象 { "key":"value" } json對(duì)象中是n個(gè)鍵值對(duì) key: 必須是字符串 value: 整形 浮點(diǎn)型 布爾 字符串 json數(shù)組 json對(duì)象 注意事項(xiàng): 在一個(gè)文件中只能存儲(chǔ)一個(gè)大的數(shù)組或者對(duì)象, 但是可以嵌套使用 原素和原始之間使用逗號(hào)間隔(一個(gè)鍵值對(duì)視為一個(gè)元素) 最后一個(gè)元素后邊沒有逗號(hào) { "lilii":"717", "tom":"nihao", "lucy":"yyyyhhhh" } ["潔潔", "姐姐"] { "潔潔":{ "father":"張三", "mother":"xxx", "sister""xxx", "favorite":["跳舞", "唱歌", "游泳"] } "姐姐":{ } }
Protocol Buffer
ASN.1 抽象語(yǔ)法標(biāo)記(Abstract Syntax Notation One)
boost 序列化的類
2. protobuf
Protobuf是一個(gè)純粹的展示層協(xié)議,可以和各種傳輸層協(xié)議一起使用,Protobuf的文檔也非常完善。google 提供了多種語(yǔ)言的實(shí)現(xiàn):java、c#、c++、go 和 python,每一種實(shí)現(xiàn)都包含了相應(yīng)語(yǔ)言的編譯器以及庫(kù)文件。
Protobuf支持的數(shù)據(jù)類型相對(duì)較少,不支持常量類型。由于其設(shè)計(jì)的理念是純粹的展現(xiàn)層協(xié)議,目前并沒有一個(gè)專門支持Protobuf的RPC框架。
2.1 操作流程
- 準(zhǔn)備數(shù)據(jù)
- 復(fù)合類型: 結(jié)構(gòu)體/ 類
- 基礎(chǔ)類型
- 創(chuàng)建一個(gè)新文件 xxx.proto
- 將我們要序列化的數(shù)據(jù) -> 寫入到proto文件
- 注意寫入有語(yǔ)法格式
- 通過(guò)命令 protoc將xxx.proto文件生成一個(gè)c++的類
- 會(huì)生成一個(gè)頭文件/ 源文件
- 操作命令-> 在window終端中: protoc xxx.proto --cpp_out=./
- 使用這兩個(gè)文件
- 文件里有對(duì)數(shù)據(jù)操作的api
- 讀數(shù)據(jù) API
- 方法名字 變量名()
- 寫數(shù)據(jù) API
- 方法名字: set_變量名(arg)
- 等等API
// 要序列化的數(shù)據(jù) struct Persion { int id; string name; string sex; // man woman int age; }; int id;
在.proto文件中定義消息格式
// protobuf的版本 syntax = "proto3"; // proto2 // 組織Persion結(jié)構(gòu)體 // 語(yǔ)法格式 message 關(guān)鍵字(相當(dāng)于被創(chuàng)建出的類的名字) { // 成員變量 數(shù)據(jù)類型 變量名 = 變量的編號(hào); // 編號(hào)從1開始, 不能重復(fù) } // .proto文件 生成 c++ 類的命令 protoc proto文件名 --cpp_out=生成目錄
具體轉(zhuǎn)換類型規(guī)則如下所示:
.proto類型 | C++類型 | 備注 |
---|---|---|
double | double | 64位浮點(diǎn)數(shù) |
float | float | 32位浮點(diǎn)數(shù) |
int32 | int32 | 32位整數(shù) |
int64 | int64 | 64位整數(shù) |
uint32 | uint32 | 32位無(wú)符號(hào)整數(shù) |
uint64 | uint64 | 64位無(wú)符號(hào)整數(shù) |
sint32 | sint32 | 32位整數(shù),處理負(fù)數(shù)效率比int32更高 |
sint64 | sint64 | 64位整數(shù),處理負(fù)數(shù)效率比int64更高 |
fixed32 | uint32 | 總是4個(gè)字節(jié)。如果數(shù)值總是比總是比228大的話,這個(gè)類型會(huì)比uint32高效。 |
fixed64 | uint64 | 總是8個(gè)字節(jié)。如果數(shù)值總是比總是比256大的話,這個(gè)類型會(huì)比uint64高效。 |
sfixed32 | int32 | 總是4個(gè)字節(jié) |
sfixed64 | int64 | 總是8個(gè)字節(jié) |
bool | bool | 布爾類型 |
string | string | 一個(gè)字符串必須是UTF-8編碼或者7-bit ASCII編碼的文本 |
bytes | string | 處理多字節(jié)的語(yǔ)言字符、如中文 |
enum | enum | 枚舉 |
message | object of class | 自定義的消息類型 |
repeated限定修飾符
用于定義一個(gè)字段可以包含多個(gè)值。它只能應(yīng)用于特定的字段類型,例如int32、string等。
使用repeated修飾符可以定義一個(gè)重復(fù)字段,表示該字段可以包含一個(gè)或多個(gè)值,并以列表的形式進(jìn)行存儲(chǔ)和傳輸。這使得我們能夠在一個(gè)字段中存儲(chǔ)多個(gè)相關(guān)的數(shù)據(jù),而無(wú)需定義多個(gè)獨(dú)立的字段。
以下是一個(gè)示例,展示了如何使用repeated修飾符創(chuàng)建一個(gè)重復(fù)字段:
message MyMessage { repeated int32 numbers = 1; repeated string names = 2; }
在上述示例中,numbers字段和names字段都被修飾為repeated,允許存儲(chǔ)多個(gè)整數(shù)和字符串值。
通過(guò)使用repeated修飾符,我們可以輕松地處理包含多個(gè)值的字段,例如迭代訪問(wèn)、添加和刪除元素等操作。
枚舉
枚舉類型是一種定義常量值列表的方式,用于表示一組相關(guān)的命名常量。它可以在消息類型中定義,并用于描述消息類型中的字段。
以下是一個(gè)示例,展示了如何使用protobuf中的枚舉類型:
// 定義枚舉 enum PhoneType { MOBILE = 0;// protbuf中第一個(gè)枚舉值必須為0 HOME = 1; WORK = 2; } message Person { string name = 1; repeated PhoneNumber phones = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; // 枚舉變量 }
在上述示例中,我們定義了一個(gè)PhoneType枚舉類型,其中包含三個(gè)常量值:MOBILE、HOME和WORK。這個(gè)枚舉類型用于描述電話號(hào)碼的類型,包括移動(dòng)電話、家庭電話和工作電話。
然后,我們?cè)赑honeNumber消息類型中使用了這個(gè)枚舉類型,將電話號(hào)碼與電話類型關(guān)聯(lián)起來(lái)。這樣,我們就可以輕松地區(qū)分不同類型的電話號(hào)碼,并按照類型進(jìn)行處理。
在protobuf中,枚舉類型的值對(duì)應(yīng)一個(gè)整數(shù),可以使用=操作符為其指定具體的值。默認(rèn)情況下,第一個(gè)枚舉值的值為0,后續(xù)的枚舉值依次遞增。如果需要指定特定的值,可以使用類似于MY_ENUM_VALUE = 100;這樣的語(yǔ)法進(jìn)行設(shè)置。
proto文件的導(dǎo)入
// Persion.proto syntax = "proto3"; // 導(dǎo)入另外一個(gè)proto文件 import "Info.proto"; enum Color { Red = 0; // protbuf中第一個(gè)枚舉值必須為0 Green = 6; Blue = 9; } message Persion { int32 id = 1; // 編號(hào)從1開始 repeated bytes name = 2; string sex = 3; int32 age = 4; Color color = 5; Info info = 6; // Info對(duì)象, 導(dǎo)入的proto文件中的類 }
// Info.proto syntax = "proto3"; message Info { bytes address = 1; // 地址 int32 number = 2; // 門牌號(hào) }
包 -> 命名空間
// Persion.proto syntax = "proto3"; // 導(dǎo)入另外一個(gè)proto文件 import "Info.proto"; // 添加命名空間 package itcast; // Persion類屬于itcast這個(gè)命名空間 enum Color { Red = 0; // protbuf中第一個(gè)枚舉值必須為0 Green = 6; Blue = 9; } message Persion { int32 id = 1; // 編號(hào)從1開始 repeated bytes name = 2; string sex = 3; int32 age = 4; Color color = 5; // 命名空間.類名 itheima.Info info = 6; // Info對(duì)象, 導(dǎo)入的proto文件中的類 }
// Info.proto syntax = "proto3"; // Persion類屬于itheima這個(gè)命名空間 package itheima; message Persion { bytes address = 1; // 地址 int32 number = 2; // 門牌號(hào) }
使用protobuf編譯器生成C++類
# protobuf編譯器, 編譯源碼得到的 protoc.exe # 語(yǔ)法 # --cpp_out 生成的c++類的位置 protoc.exe xxx.proto --cpp_out=目錄
使用C++ API來(lái)讀寫消息
- 讀:
變量名()
- 寫:
set_變量名(arg1, arg2, ...)
?總結(jié)
- 效率和緊湊性:protobuf使用二進(jìn)制編碼,提供了高效的數(shù)據(jù)傳輸和緊湊的數(shù)據(jù)存儲(chǔ),相對(duì)于文本格式,可以節(jié)省帶寬和存儲(chǔ)空間。
- 跨平臺(tái)和可擴(kuò)展性:protobuf支持多種編程語(yǔ)言,包括C++、Java、Python等,可以在不同平臺(tái)和語(yǔ)言之間進(jìn)行數(shù)據(jù)交換。它還支持向前和向后兼容,可以在消息類型更新時(shí)保持?jǐn)?shù)據(jù)的兼容性。
- 結(jié)構(gòu)化數(shù)據(jù)定義:protobuf使用.proto文件來(lái)定義消息類型和字段,提供了結(jié)構(gòu)化的數(shù)據(jù)模型,使得數(shù)據(jù)的組織和訪問(wèn)更加清晰和靈活。
- 強(qiáng)類型和類型安全:protobuf使用強(qiáng)類型系統(tǒng),可以在編譯時(shí)檢查類型錯(cuò)誤,避免在運(yùn)行時(shí)出現(xiàn)錯(cuò)誤。這提供了更好的類型安全性和代碼可靠性。
- 支持多種數(shù)據(jù)類型:protobuf支持各種基本數(shù)據(jù)類型(如整數(shù)、字符串、布爾值等),以及復(fù)雜的數(shù)據(jù)類型(如嵌套消息、枚舉等),可以靈活地描述和處理各種數(shù)據(jù)結(jié)構(gòu)。
- 序列化和反序列化:protobuf提供了自動(dòng)生成的序列化和反序列化代碼,使得數(shù)據(jù)的序列化和反序列化過(guò)程簡(jiǎn)單而高效。它還支持壓縮技術(shù),可以減小數(shù)據(jù)大小,提高傳輸效率。
- 可讀性和可維護(hù)性:由于protobuf使用結(jié)構(gòu)化的數(shù)據(jù)模型和明確的消息類型定義,使得代碼更具可讀性和可維護(hù)性。同時(shí),它也提供了版本控制機(jī)制,方便進(jìn)行更新和演進(jìn)。
到此這篇關(guān)于protobuf 序列化和反序列化的文章就介紹到這了,更多相關(guān)protobuf 序列化和反序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python將Office文檔(Word、Excel、PDF、PPT)轉(zhuǎn)為OFD格式的實(shí)現(xiàn)方法
OFD(Open Fixed-layout Document )是我國(guó)自主制定的一種開放版式文件格式標(biāo)準(zhǔn),如果想要通過(guò)Python將Office文檔(如Word、Excel或PowerPoint)及PDF文檔轉(zhuǎn)換為OFD格式,可以參考本文中提供的實(shí)現(xiàn)方法,需要的朋友可以參考下2024-06-06全面了解Python環(huán)境配置及項(xiàng)目建立
下面小編就為大家?guī)?lái)一篇全面了解Python環(huán)境配置及項(xiàng)目建立。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06Python實(shí)現(xiàn)同時(shí)調(diào)用多個(gè)GPT的API
這篇文章主要為大家詳細(xì)介紹了Python如何實(shí)現(xiàn)同時(shí)調(diào)用多個(gè)GPT的API,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-09-09python實(shí)現(xiàn)將代碼轉(zhuǎn)成不可反編譯的pyd文件
pyc文件用于提高加載速度,部分源碼可讀,而pyd文件提供更好的保密性,是編譯后的二進(jìn)制動(dòng)態(tài)鏈接庫(kù),當(dāng)有些模塊的代碼需要一定的保密性,這個(gè)時(shí)候就需要考慮pyc和pyd文件了,本文給大家介紹了python實(shí)現(xiàn)將代碼轉(zhuǎn)成不可反編譯的pyd文件,需要的朋友可以參考下2024-11-11Python實(shí)現(xiàn)批量修改Word文檔中圖片大小并居中對(duì)齊
這篇文章主要介紹了如何利用Python實(shí)現(xiàn)批量修改Word文檔中圖片大小并居中對(duì)齊,文中通過(guò)代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-08-08django2.2 和 PyMySQL版本兼容問(wèn)題
這篇文章主要介紹了django2.2 和 PyMySQL版本兼容問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02詳解解決Python memory error的問(wèn)題(四種解決方案)
這篇文章主要介紹了詳解解決Python memory error的問(wèn)題(四種解決方案),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08python正常時(shí)間和unix時(shí)間戳相互轉(zhuǎn)換的方法
這篇文章主要介紹了python正常時(shí)間和unix時(shí)間戳相互轉(zhuǎn)換的方法,涉及時(shí)間字符串與Unix時(shí)間戳的實(shí)現(xiàn)與轉(zhuǎn)換技巧,需要的朋友可以參考下2015-04-04使用 Python ssh 遠(yuǎn)程登陸服務(wù)器的最佳方案
這篇文章主要介紹了使用 Python ssh 遠(yuǎn)程登陸服務(wù)器的最佳方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03