lua里使用proto buffer
protoc-gen-lua
官方不維護了,自己維護個:protoc-gen-lua
- int64支持,將64位int轉換成lua的string。
- message相互嵌套引用,不依賴定義的順序。
- import的bug
protoc-gen-lua int64支持
lua 5.1里使用double表示number,然后double最多兼容int53。
項目中協議已經使用int64了,為了支持int64,將int64全部轉換成string來處理。
看懂protoc-gen-lua的decode、encode代碼,在熟悉下protbuf的存儲格式。然后修改編解碼部分。
protoc-gen-lua import bug
官方的protoc字段名都是定義成local變量,外部不可訪問,import引用就掛了。
修改后,字段名都當成module里的全局變量,損失性能,但是外部可以訪問。
proto buffer的一些細節
google開源的序列化工具,類似json,二機制格式。
存儲格式
protobuf把message保存成一系列key-value對。
key由每個field的index和type來確定,算法key = (index<<3) | type
。使用varint格式保存,所以index小於16才能用一個字節保存。
value隨type不同,有不同的保存方式。
type | 對於的message的類型 | 編碼存儲說明 |
0 | int32, int64, uint32, uint64, sint32, sint64, bool, enum |
varint、zigint |
1 | fixed64, sfixed64, double | 64-bit |
2 | string, bytes, embedded messages, packed repeated fields | 長度(varint) + 內容 |
5 | fixed32, sfixed32, float |
32-bit |
額外說明下packed repeated fields
對於repeated類型的字段,可以不用連續存儲,每個都是key+value
,只是key
都是一樣的。
使用packed可以達到壓縮key的效果,整體連續存儲為key+size+value+value+...
。
例子:
message Test {
repeated int32 d = 1 [packed=true];
}
假設添加兩個數字`1,128`。
序列號結果:
08 key
03 字節數
01 數字1
80 01 數字128
varint
變長int,用一個或多個字節表示整數。值越小,字節數越少。整數在這里都是當成無符號。
具體這么做:
- varint的每個字節的最高bit位表示數字序列有沒有結束。1表示沒有結束,0表示結束。
- 每個字節的剩余7個bit位存儲數字的有效bit位。如果數字小於128,就只要1個字節了,如64表示為
01000000
。 - 字節序使用的小端序。
數字150轉換過程:
- 二機制表示
10010110
- 划分7bit位
00000001 00010110
- 反序
00010110 00000001
- 設置最高位
10010110 00000001
zigint
varint有個缺點,如果是負數,就達不到壓縮字節數的效果。因為最高位是1,是個有效位。
如int64類型的-1
,要使用10個字節,而絕對值只有1。
zigint就是針對這種情況處理的。先用zigzag重新編碼下數字,再使用varint存儲。
int64轉換公式:
zig_int = (signed_int << 1) ^ (signed_int >> 63)
signed_int = (zig_int >> 1) ^ - (int64_t)(n & 1)
這種表示方法類似於1個bit位保存符號為,其他的保存絕對值。
但是64用zigint標識就得兩個字節了,保存的是128。
搜集的資料等
- protobuf序列化原理
- Google Protocol Buffer 的使用和原理
- Gooogle Protoc-gen-lua
- protoc-gen-lua github 好像不維護了
- protoc-gen-lua int64支持,有條件的,實際是int32才能不出錯
- protoc-gen-lua int64支持,將64位int轉換成lua的string,修改不少bug