現在在網絡通信和通用數據交換等應用場景中經常使用的技術是 JSON 或 XML以及 Google 的 Protobuf。Protobuf是後起之秀,其在效率、兼容性等方面更加出色。很多人在項目技術選項中,尤其是網絡通信、通用數據交換等場景應該會優先選擇Protobuf。
白鷺引擎首席架構師王澤曾經發布了一個開源項目Protobuf-egret,提供了一個可以適配微信小遊戲的Protobuf 類庫以及對應的代碼生成工具,並且這個工具不僅限於白鷺引擎,即使是使用其他 HTML5 遊戲引擎的開發者也可以使用。本文將從基礎講解,讓大家認識Protobuf和如何在自己的項目中使用Protobuf這種數據格式以及開源項目Protobuf-egret開源庫的使用。
1、什麼是Protobuf
Protobuf是Google開源的一款類似於Json,XML數據交換格式,其內部數據是純二進制格式,不依賴於語言和平臺,具有簡單,數據量小,快速等優點.
2、Protobuf與XML,Json的比較
1、json: 一般的web項目中,最流行的主要還是json。因爲瀏覽器對於json數據支持非常好,有很多內建的函數支持。
2、XML: 在webservice中應用最爲廣泛,但是相比於json,它的數據更加冗餘,因爲需要成對的閉合標籤。json使用了鍵值對的方式,不僅壓縮了一定的數據空間,同時也具有可讀性。
3、Protobuf:是谷歌開源的一種數據格式,適合高性能,對響應速度有要求的數據傳輸場景。
相對於其它Protobuf更具有優勢
1:序列化後體積相比json和XML很小,適合網絡傳輸
2:支持跨平臺多語言
3:消息格式升級和兼容性還不錯
4:序列化反序列化速度很快,快於Json的處理速度
結論:
在一個需要大量的數據傳輸的場景中,如果數據量很大,那麼選擇Protobuf可以明顯的減少數據量,減少網絡IO,從而減少網絡傳輸所消耗的時間。
3、Protobuf如何使用
因爲profobuf是二進制數據格式,需要編碼和解碼。數據本身不具有可讀性。因此只能反序列化之後得到真正可讀的數據。那麼,在項目中如何使用呢?
首先,編寫Protobuf格式的消息文件(以.proto爲後綴的文件);
下面就是我編寫的一個test.proto文件
syntax = "proto3";//語法是proto3的語法
package test;//給每一個文件指定一個package值。
//每一個數據結構就是一個消息 有message關鍵字定義
message user_login{
//限定修飾符 | 數據類型 | 字段名稱 = | 字段編碼值 | [字段默認值]
required int32 userId = 1;
required string userName = 2;
require string password = 3;
}
ps:更多的語法規則大家可以百度查看,這裏不詳細講解了。
其次,使用Protobuf的編譯器編譯消息文件XXX.proto;
google 提供了多種語言的實現:C++、C#、Objective-C、Java、JavaScript、Ruby、PHP、Dart、Go 語言,每一種實現都包含了相應語言的編譯器以及文件。
最後,使用編譯好對應語言的類文件進行消息的序列化和反序列化
4、egret集成Protobuf
如何在egret遊戲項目中使用Protobuf數據格式進行網絡通信和數據交換呢?
白鷺引擎首席架構師王澤曾經發布了一個開源項目Protobuf-egret,提供了一個可以適配微信小遊戲的Protobuf 類庫以及對應的代碼生成工具,並且這個工具不僅限於白鷺引擎,即使是使用其他 HTML5 遊戲引擎的開發者也可以使用。相關內容大家可以再次閱讀《如何在微信小遊戲中使用Protobuf》(https://mp.weixin.qq.com/s/WNdIRxZEfpKFpUdFdlr5Mg)。接下來,我再更加詳細的介紹一下我的使用過程。
4.1 介紹egret Protobuf庫
特性
- 提供 Protobuf.js 基礎運行時庫
- 提供命令行腳本,將 protofile 生成 JavaScript 代碼
- 生成正確的 .d.ts 代碼,以方便 TypeScript 項目使用
- 一鍵配置白鷺引擎的配置文件,無需開發者手動修改配置即可在項目中直接集成
- 本項目雖然名爲 egret Protobuf ,但是理論上支持所有 HTML5 遊戲引擎。歡迎使用 PIXI.js , Cocos2d-js , LayaAir 等其他引擎的開發者使用本庫。
原理
封裝了 Protobufjs 庫及命令行。使用 Protobufjs 6.8.4 的運行時庫。
Protobufjs 自身存在着 pbts 命令,雖然也可以生成 .d.ts 文件,但是在全局模式而非 ES6 module 的情況下存在一些錯誤,本項目致力於解決這個問題,使 Protobufjs 可以在非 ES6 模塊項目中(比如白鷺引擎)中也可以使用 Protobufjs
Protobufjs 提供了多種使用方式,由於微信小遊戲禁止 eval , new Function 等動態代碼形式,所以本項目只提供了生成代碼的形式,不支持通過 Protobuf.load('awesome.proto')
的方式(因爲這種方式也無法在微信小遊戲中運行)。
4.2 安裝egret Protobuf庫
第一步,首先檢查你是否安裝了node.js以及npm,沒有安裝的自行安裝。
第二步,在自己的電腦上安裝Protobufjs庫以及egret Protobuf庫。
Protobuf.js是基於ByteBuffer.js的Protocol Buffers純JavaScript實現,主要功能是解析.proto文件,構建Message類,編碼解碼。
#安裝Protobufjs庫
npm install [email protected] -g
#安裝egret Protobuf庫
npm install @egret/Protobuf -g
4.3 使用egret Protobuf庫
假設用戶有個名爲 egret-project 的白鷺項目;
第一步,cd到egret-project目錄下
cd egret-project
第二步,將egret Protobuf代碼以及項目結構拷貝至白鷺項目
pb-egret add
執行之後的項目目錄如下圖:
第三步,將XXX.proto文件拷貝至protofile目錄中。
第四步,將XXX.proto文件在peorobuf/bundles目錄下生成對應的js文件和d.ts文件。
pb-egret generate
4.4 認識Protobuf-bundles.d.ts
方法名 | 描述 |
---|---|
create | 從一組滿足有效消息要求的屬性中創建一個新消息實例,如果適用,建議首選create而非fromObject,因爲create不會執行可能存在冗餘的轉換。 |
encode | 對消息實例或有效的純JavaScript對象進行編碼,encode不隱式的驗證消息,而由用戶確定有效負載是有效消息。 |
encodeDelimited | 將protobuffer解碼爲消息實例,如果required字段缺少則會拋出util.ProtocolError錯誤。 |
decodeDelimited | 工作方式類似於decode函數,會另外讀取一個消息的長度作爲變量的預設值。 |
verify | 驗證普通JavaScript對象是否滿足有效消息的要求,以確保無錯誤的進行加密編碼(encode)。verify不拋出錯誤而會將錯誤消息作爲字符串返回。 |
我們看看Protobuf如何序列化和反序列化
Main.ts
var user = {
"userId":1,
"userName":"psyche"
}
//驗證user是否滿足要求
var ret = test.user_login.verify(user);
console.log(ret);
//如果正確,ret是null 否則是返回字符串
if(ret){
throw Error(ret);
}
var msg = test.user_login.create(user);
console.log(msg);
//將實例編譯成二進制流
var buf = test.user_login.encode(user).finish();
console.log(buf);
//解析二進制流
var de_buf = test.user_login.decode(buf);
console.log(de_buf);
本次關於egret中使用Protobuf的介紹到此爲止。