Protobuf 數(shù)據(jù)格式

Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.

簡單來說组哩,Protocol Buffers 是一種和語言平臺都沒關(guān)的數(shù)據(jù)交換格式。

關(guān)于 Protobuf 在iOS下的使用請看上篇文章 iOS 的 Protocol Buffer 簡單使用

Varint

Protobuf 序列化后的二進(jìn)制數(shù)據(jù)消息非常的緊湊,這得益于 Protobuf 所采用的 Varint

Varint 是一種緊湊的表示數(shù)字的方法,它用一個或多個字節(jié)來表示一個數(shù)字,值越小的數(shù)字使用越少的字節(jié)數(shù)揣钦。這能減少用來表示數(shù)組的字節(jié)數(shù)。

比如對于 int32 類型的數(shù)字,一般需要4個 byte 來標(biāo)識聂抢。但是采用 Varint,對于很小的 int32 類型的數(shù)字棠众,也能用1個 byte 來標(biāo)識琳疏。如果數(shù)字很大,也就需要5個 byte 來表示了闸拿。但是空盼,一般情況下很少會出現(xiàn)數(shù)字都是大數(shù)的情況下轻腺。

正常情況下虑椎,每個 byte 的8個 bit 位都用于存儲數(shù)據(jù)用提澎,而在 Varint 中肛度,每個 byte 的最高位的 bit 有著特殊的含義咖杂,如果該位為1鸽扁,表示后續(xù)的 byte 也是該數(shù)據(jù)的一部分谭网;如果該位為0致份,則結(jié)束智袭。其他的7個 bit 位都用來表示數(shù)據(jù)奔缠。因此小于127的 int32 數(shù)字都可以用一個 byte 表示,而大于等于 128 的數(shù)字:如128吼野,則會用兩個字節(jié)表示:1000 0000 0000 0001(采用的是小端模式)校哎,311則表示:1011 0111 0000 0010

下圖演示了 Protobuf 如果通過2個 byte 解析出 128。Protobuf 字節(jié)序采用的是 little-endian(小端模式)

Varint

int32 數(shù)據(jù)類型能表示負(fù)數(shù)瞳步,負(fù)數(shù)的最高位為1闷哆,如果負(fù)數(shù)也使用這種方式表示會出現(xiàn)一個問題,int32 總是需要5個字節(jié)单起,int64 總是需要10個字節(jié)抱怔。所以 Protobuf 定義了另外一種類型 sint32, sint64,采用 ZigZag 編碼嘀倒,所有的負(fù)數(shù)都使用正數(shù)表示屈留,計(jì)算方式為:

  • sint32

    (n << 1) ^ (n >> 31)
    
  • sint64

    (n << 1) ^ (n >> 63)
    
Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

Message Structure

Protobuf 消息是一系列的鍵值對組成局冰。消息的二進(jìn)制版本僅使用 field 數(shù)字當(dāng)作 key,不同 field 的屬性和類型只能通過消息類型的定義 (即 .proto 文件) 在解碼端確定灌危。如果消息中不存在該 field康二,那么序列化后的 Message Buffer 中也不會有該 field,這些特性都有助于節(jié)約消息本身的大小勇蝙。

Message Buffer

Key 用來標(biāo)識具體的 field沫勿,在解包的時候,Protobuf 根據(jù) key 就能知道相應(yīng)的 Value 對應(yīng)于消息中的哪一個field味混,數(shù)據(jù)類型是哪個類型产雹。

Key 的定義如下:

(field_number << 3) | wire_type

Key 由兩部分組成:第一個部分是 field_number,比如上篇文章定義的消息 FooSimpleMessage 中的 msgId 屬性的 field_number 為1翁锡;第二部分為 wire_type蔓挖,表示 Value 的傳輸類型

表1. Wire 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

在之前的例子中,msgId 采用的數(shù)據(jù)類型為 int32盗誊,因此對應(yīng)的 wire_type 為0时甚,所以對應(yīng)的 tag 為

(1 << 3) | 0 = 0x08

FooSimpleMessage 的 msgContent,field_number 為2哈踱,wire_type 為2,所以對應(yīng)的 tag 為

(2 << 3) | 2 = 0x12

對應(yīng) Length-delimited 的 wire type梨熙,后面緊跟著的 Varint 類型表示數(shù)據(jù)的字節(jié)數(shù)开镣。所以 msgContent 的 key 后面緊跟著的 0x1a 表示后面的數(shù)據(jù)長度為10個字節(jié),"A protobuf message content" 的 ASCII 值即為:0x41 0x20 0x70 0x72 0x6f 0x74 0x6f 0x62 0x75 0x66 0x20 0x6d 0x65 0x73 0x73 0x61 0x67 0x65 0x20 0x63 0x6f 0x6e 0x74 0x65 0x6e 0x74

Demo 里面定義的 msg 對象咽扇,其序列化后的數(shù)據(jù)的十六進(jìn)制表示應(yīng)該為 0801121a 41207072 6f746f62 7566206d 65737361 67652063 6f6e7465 6e74

FooSimpleMessage *msg = [[FooSimpleMessage alloc] init];
msg.msgId = 1;
msg.msgContent = @"A protobuf message content";
NSLog("%@", msg.data);

運(yùn)行demo邪财,打印一下結(jié)果和猜想的一樣:

<0801121a 41207072 6f746f62 7566206d 65737361 67652063 6f6e7465 6e74>

參考地址:Protocol-buffers Encoding

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市质欲,隨后出現(xiàn)的幾起案子树埠,更是在濱河造成了極大的恐慌,老刑警劉巖嘶伟,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怎憋,死亡現(xiàn)場離奇詭異,居然都是意外死亡九昧,警方通過查閱死者的電腦和手機(jī)绊袋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铸鹰,“玉大人癌别,你說我怎么就攤上這事√A” “怎么了展姐?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵躁垛,是天一觀的道長。 經(jīng)常有香客問我圾笨,道長缤苫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任墅拭,我火速辦了婚禮活玲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谍婉。我一直安慰自己舒憾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布穗熬。 她就那樣靜靜地躺著镀迂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唤蔗。 梳的紋絲不亂的頭發(fā)上探遵,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音妓柜,去河邊找鬼箱季。 笑死,一個胖子當(dāng)著我的面吹牛棍掐,可吹牛的內(nèi)容都是我干的藏雏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼作煌,長吁一口氣:“原來是場噩夢啊……” “哼掘殴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粟誓,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤奏寨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鹰服,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體病瞳,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年获诈,在試婚紗的時候發(fā)現(xiàn)自己被綠了仍源。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡舔涎,死狀恐怖笼踩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情亡嫌,我是刑警寧澤嚎于,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布掘而,位于F島的核電站,受9級特大地震影響于购,放射性物質(zhì)發(fā)生泄漏袍睡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一肋僧、第九天 我趴在偏房一處隱蔽的房頂上張望斑胜。 院中可真熱鬧,春花似錦嫌吠、人聲如沸止潘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凭戴。三九已至,卻和暖如春炕矮,著一層夾襖步出監(jiān)牢的瞬間么夫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工肤视, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留档痪,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓钢颂,卻偏偏與公主長得像钞它,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子殊鞭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

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