pomelo原始碼解析之模組解析(二)

2021-09-05 09:16:16 字數 4108 閱讀 8253

tag過大怎麼辦

官方wiki:訊息壓縮

protobuf是一種序列化技術,能夠大大減少傳輸無效資料

先看一下傳統的c++通訊格式

#pragma pack(1)

struct player

;#pragma pack()

因為名字有長有短,需要定義乙個字元陣列。也就是這個訊息必然會傳送32+4=36個位元組。實際運用中會有很多的浪費。

而protobuf所採用的資料格式會去掉那些無效的資料,可以很大的壓縮整個訊息流的長度。

同時也更方便的使用變長字串。與json相比,不需要在訊息流中定義變數名字。

採用variant編碼。第乙個位元組標視後續資料的tag以及type。

後續每個位元組的最高位為控制位,剩餘7位儲存資料。如果最高位位1,代表下乙個位元組依舊為本次的資料。

例如傳輸乙個 unsigned int a = 1

這個a變數序列化後的二進位制為兩個位元組 (pomelo-protobuf採用的是小端格式,以小端儲存為例,下同)

第乙個位元組:其中第一位flag,中間4位表示tag(使用者設定,4位表示不下怎麼辦看最後),最後3位表示type,也就是說最多支援2^3=8種型別

flag

tagtype

0***x

000flag之後的位元組是具體的value,最高位是標誌位,為1的話表示下乙個位元組依舊為本次的資料

flag

value

00000001

如果傳輸的資料大於127,例如200的二進位制表示為11001000。序列後為3個位元組,第乙個位元組同上。第二三個位元組如下:

flag

value

11001000

flag

value

00000001

有符號整型的話。如果是整數,直接*2儲存 負數的話 *2-1儲存。取值的話根據%2的餘數判斷符號

字串的話,需要在flag之後的位元組寫入長度

在專案/config 內有clientprotos.jsonserverprotos.json兩個配置檔案,分別對應客戶端的訊息和伺服器的訊息

配置格式:支援required message repeated關鍵字 檢視原始碼得知optional與required關鍵字功能相同

,"repeated path path":2

,"required float speed":3

}}

上文定義了乙個onmove的訊息。裡面包含有3個字段 entityid path speed。最後的數字就是tag(不允許重複)

其中path為自定義型別。也就是message定義的型別。並且是個陣列。

翻譯成c++是這樣的:

struct path

;struct onmove

;

pomelo-protobuf內建資料型別:pomelo-protobuf/lib/constant.js

module.exports =

}

修改pomelo-protobuf/test下的部分**,測試用例如下

定義訊息結構如下:

}

傳送資料如下:

tc[

'pomelo-protobuf-test']=

;

除錯可見被序列化成了671個位元組的二進位製流:

第乙個位元組=10,tag=1就是我們定義的那個,type=2也就是string或者message型別。

解析器本身也會讀取結構定義,所以知道第乙個型別具體是什麼。詳見decoder.decodemsg
flag

tagtype

00001

010第二個位元組=4,代表字串長度為4

flag

value

00000100

第三個位元組=97,字串資料開始,97就是字元『a』 。3-5位元組一次是bcd

flag

value

01100001

第乙個位元組=18: tag=2,type=2

flag

tagtype

000010

010第二個位元組=138,實際資料為10需要聯絡下乙個位元組

flag

value

100001010

第三個位元組=5。聯絡上乙個位元組10,最終長度為5*2^8+10=650位元組

flag

value

00000110

其餘位元組就是字串內容了,直接跳到buffer[659]

第乙個位元組=24: tag=3,type=0

flag

tagtype

000011

000第二個位元組=127,實際資料為127

flag

value

01111111

第乙個位元組=32: tag=4,type=0

flag

tagtype

000100

000第二個位元組=200,flag=1代表後續還有資料,value=72

flag

value

11001000

第三個位元組=1,value=1。結合第二個位元組,這個字段:1*2^8+72=200

flag

value

00000001

第乙個位元組=40: tag=5,type=0

flag

tagtype

000101

000第二個位元組=239,flag=1代表後續還有資料,value=101

flag

value

11101111

第三個位元組=1,value=1。結合第二個位元組,這個字段:1*2^8+101=239。解析器知道該字段為有符號的。

%2=1,所以最終結果為 (239+1)/2 *(-1)=-120**在:encoder.encodesint32

flag

value

00000001

第乙個位元組=48: tag=6,type=0

flag

tagtype

000110

000第二個位元組=2,代表該陣列有2個元素,分別是1和2。陣列實際就是遞迴分析,只是裡面元素不再需要flag位元組,因為陣列型別已經標註過了。

我們可以分析下原始碼寫入tag的地方

function

encodetag

(type, tag)

實際上也就是tag*8+type位元組當作uint32寫入。

讀取就是

function

gethead()

;}encoder.

decodeuint32

=function

(bytes)

}return n;};

function

getbytes

(flag)

while

(b >=

128);if

(!flag)

return bytes;

}

也就是說tag超過4位表示的依舊可以支援。

測試如下。設定第乙個元素tag=50

第乙個位元組=146,因為超過128會繼續讀取第二個位元組3。合併成整數3*128+18=402 注意第一位元組的146要去掉最高位

計算出tag=402/8=50,type=402%8=2

pomelo原始碼解析之模組解析(五)

var sio require sioconnector port,host,opts sio.on connection function siosocket 再看一下siosocket的實現 繼承自eventemitter 發現處理了disconnect,error,message訊息,原封不動...

pomelo原始碼解析之元件Remote

首先提出問題 1.元件remote是什麼?2.remote的作用是什麼?remote模組是遠端通訊模組服務端監聽模組,作用是作為各個模組間通訊物件的存在。變數中儲存.return paths var paths var role master server should not come here ...

JDk原始碼解析之四 Vector原始碼解析

具體的三個屬性 解釋看圖中注釋。vector沒有採取arraylist臨界值擴容的辦法,而是每次不夠的時候,直接根據capacity的值來增加。具體怎麼增加後面會說。vector的構造方法如下。簡單粗暴,如果呼叫無參建構函式,直接就將初始容量設定成了10,最終在右側的構造方法裡,將陣列的長度設定為1...