protobuf使用及原理


title: ProtoBuf3定義及數(shù)據(jù)加密和解密
author: 獨孤流
date: 2024-05-29 01:12:00 +0800
categories: [加解密]
tags: [proto] # TAG names should always be lowercase


參考:

demo: https://github.com/h42330789/StudyProto

前言

前后端數(shù)據(jù)傳輸格式,從遠古的xml到了現(xiàn)在通用的json格式,但是在IM系統(tǒng)中,為了數(shù)據(jù)量精簡以及嚴格約定各個字段,使用的一般都是proto

一丁鹉、proto優(yōu)缺點

優(yōu)點:
1、傳輸數(shù)據(jù)精簡,數(shù)量小
2位仁、同時前后端都使用了一份源文件生成的模型對象,proto有變更時能及時知道哪里部分有修改方椎,也方便后端往前兼容歷史版本
3聂抢、傳輸過程中不可讀,天然的多了一道加密過程
4棠众、可以直接使用枚舉值
5琳疏、不需要自己想名字定義模型,對于起名字頭疼的人尤其簡單輕松
缺點:
1、傳輸過程匯總不可讀空盼,沒法查看數(shù)據(jù)
2疮薇、由于proto嚴格控制數(shù)據(jù)順序、類型我注,只要類型和順序修改就會解析不了按咒,需要寫相關(guān)接口的人要充分熟悉proto的特性,否則出現(xiàn)了解析出錯很難排查問題

二但骨、安裝proto生產(chǎn)swift文件的環(huán)境

1励七、使用命令行工具Terminal使用homebrew安裝

brew install swift-protobuf

2、生成proto文件對應的swift文件

// protoc --swift_out=生成文件的文件 proto源文件地址
// 以test.proto為例
protoc --swift_out=. test.proto

三奔缠、xxx.proto文件的寫法

test.proto為例

syntax = "proto3";
option java_package="com.xxx.xxxx.pb";
option java_outer_classname="TestProto";
//protoc.exe  -I=. --java_out=../src test.proto

// 客戶端詳情
message ClientInfo {
    string     token      = 1; // 登錄時的授權(quán)token
    string     macId      = 2; // 生成的唯一號
    int32      version         = 3; // 應用版本號
    int32      language        = 4; // 系統(tǒng)語言
}

// 公共的返回結(jié)果
message CommonResult {
    int32   errCode       = 1; // 錯誤碼
    string  errMsg        = 2; // 錯誤內(nèi)容
    string  flag          = 3; // 擴展字段
}

// 性別
enum Gender {
    Male  = 0; // 男生
    Female   = 1; // 女生
}

// 咨詢列表[biz/stus/students]
message StudentsReq {
    ClientInfo     clientInfo     = 1; // 對象:客戶端信息
    Gender   gender  = 2;// 枚舉:性別
    repeated  int32   gradeList  = 3;// 數(shù)組:年級
    string   name  = 4;// 字符串:名稱
    int32 pageNum  = 5;// 數(shù)字
    int32 pageSize = 6;// 數(shù)字
}

// 學生列表
message StudentsResp {
    CommonResult   commonResult   = 1; // 結(jié)果信息
    repeated BaseStudent students = 2;// 列表
    int32 count = 3; //
}

message BaseStudent {
    int64       stuId          = 1; // 學號
    string      name       = 2; // 名字
    string      pic         = 3; // 頭像
    int32       age        = 4; // 年齡
    string      desc  = 5; // 簡介
    Gender      gender  = 6;// 性別
}

使用命令行生產(chǎn)swift后的源碼test.pb.swift如下:protoc --swift_out=. test.proto

四掠抬、Proto數(shù)據(jù)內(nèi)容的加密與解密

4.0 項目里引入proto類庫Podfile

target 'TestProto' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for TestProto
  pod 'SwiftProtobuf', '~> 1.18.0'

  target 'TestProtoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'TestProtoUITests' do
    # Pods for testing
  end

end

4.1 Proto結(jié)構(gòu)體變成Data

// 將proto轉(zhuǎn)換成data, 然后再將data當成request里的body發(fā)送到服務端
var clientInfo = ClientInfo()
clientInfo.language = 2
clientInfo.version = 122
clientInfo.macID = "xxxx"
clientInfo.token = "yyyyyy"

var reqMessage = StudentsReq()
reqMessage.clientInfo = clientInfo
reqMessage.gender = .male
reqMessage.grade = 2
reqMessage.pageNum = 1
reqMessage.pageSize = 30

if let postData = try? reqMessage.serializedData() {
    var request = URLRequest(url: URL(string: "https://xxx.xxx/biz/stus/students")!)
    request.httpBody = postData
    // 發(fā)起請求
    URLSession.shared.dataTask(with: request, completionHandler: {_,_,_ in
        
    })
}

1. Varint 編碼每一個字節(jié)8位=(msb位 + 7位內(nèi)容)

原理
Varint 是一種緊湊的表示數(shù)字的方法校哎。它用一個或多個字節(jié)來表示一個數(shù)字两波,值越小的數(shù)字使用越少的字節(jié)數(shù)。這能減少用來表示數(shù)字的字節(jié)數(shù)闷哆。

Varint 中的每個字節(jié)(最后一個字節(jié)除外)都設置了最高有效位(msb)腰奋,這一位表示下一個字節(jié)(8位)是否任然為本數(shù)字的內(nèi)容,只有當msb為0時表示本數(shù)字結(jié)束抱怔。每個字節(jié)的低 7 位用于以 7 位組的形式存儲數(shù)字的二進制補碼表示劣坊,最低有效組首位。\

最高位為1代表后面7位仍然表示數(shù)字屈留,否則為0局冰,后面7位用原碼補齊。

如果用不到 1 個字節(jié)灌危,那么最高有效位設為 0 康二,如下面這個例子,1 用一個字節(jié)就可以表示勇蝙,所以 msb 為 0.

0000 0001

如果需要多個字節(jié)表示沫勿,msb 就應該設置為 1 。例如 300浅蚪,如果用 Varint 表示的話:

1010 1100 0000 0010

編碼方式

1)將被編碼數(shù)轉(zhuǎn)換為二進制表示

2)從低位到高位按照 7位 一組進行劃分

3)將大端序轉(zhuǎn)為小端序藕帜,即以分組為單位進行首尾順序交換

因為 protobuf 使用是小端序,所以需要轉(zhuǎn)換一下
4)給每組加上最高有效位(最后一個字節(jié)高位補0惜傲,其余各字節(jié)高位補1)組成編碼后的數(shù)據(jù)。

5)最后轉(zhuǎn)成 10 進制贝攒。

[圖片上傳失敗...(image-ba6ebe-1717428886556)]

圖中對數(shù)字123456進行 varint 編碼:

1)123456 用二進制表示為1 11100010 01000000盗誊,
2)每次從低向高取 7位 變成111 1000100 1000000
3)大端序轉(zhuǎn)為小端序,即交換字節(jié)順序變成1000000 1000100 111
4)然后加上最高有效位(即:最后一個字節(jié)高位補0,其余各字節(jié)高位補1)變成11000000 11000100 00000111
5)最后再轉(zhuǎn)成 10進制哈踱,所以經(jīng)過 varint 編碼后 123456 占用三個字節(jié)分別為192 196 7荒适。
解碼的過程就是將字節(jié)依次取出,去掉最高有效位开镣,因為是小端排序所以先解碼的字節(jié)要放在低位刀诬,之后解碼出來的二進制位繼續(xù)放在之前已經(jīng)解碼出來的二進制的高位最后轉(zhuǎn)換為10進制數(shù)完成varint編碼的解碼過程。

wire-type 名稱 說明 類型
0 Varint 可變長整型 非ZigZag編碼類型:int32, uint32, int64, uint64, bool, emum,ZigZag編碼類型:sint32, sint64
1 64-bits 固定8個字節(jié)大小 fixed64, sfiexed64, double
2 Length-delimited Length + Body string, bytes, embedding message, packed repeated
5 32-bits 固定4個字節(jié)大小 fixed32, sfixed32, float

注:wire_type3-Strart Group邪财、4-End Group 的編碼類型官方已經(jīng)棄用陕壹,所以這里也不在介紹。

Tag實現(xiàn)的結(jié)果

[7] [6] [5] [4] [3] [2]  [1]  [0]
|<----- field ----->|<-- wire -->|
        number           type 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末树埠,一起剝皮案震驚了整個濱河市糠馆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怎憋,老刑警劉巖又碌,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绊袋,居然都是意外死亡毕匀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門癌别,熙熙樓的掌柜王于貴愁眉苦臉地迎上來期揪,“玉大人,你說我怎么就攤上這事规个》镅Γ” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵诞仓,是天一觀的道長缤苫。 經(jīng)常有香客問我,道長墅拭,這世上最難降的妖魔是什么活玲? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮谍婉,結(jié)果婚禮上舒憾,老公的妹妹穿的比我還像新娘。我一直安慰自己穗熬,他們只是感情好镀迂,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唤蔗,像睡著了一般探遵。 火紅的嫁衣襯著肌膚如雪窟赏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天箱季,我揣著相機與錄音涯穷,去河邊找鬼。 笑死藏雏,一個胖子當著我的面吹牛拷况,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掘殴,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼赚瘦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了杯巨?” 一聲冷哼從身側(cè)響起蚤告,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎服爷,沒想到半個月后杜恰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡仍源,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年心褐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笼踩。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡逗爹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嚎于,到底是詐尸還是另有隱情掘而,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布于购,位于F島的核電站袍睡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肋僧。R本人自食惡果不足惜斑胜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嫌吠。 院中可真熱鬧止潘,春花似錦、人聲如沸辫诅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泥栖。三九已至簇宽,卻和暖如春勋篓,著一層夾襖步出監(jiān)牢的瞬間吧享,已是汗流浹背魏割。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钢颂,地道東北人钞它。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像殊鞭,于是被迫代替她去往敵國和親遭垛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容