现在在网络通信和通用数据交换等应用场景中经常使用的技术是 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 Protobufjs@6.8.4 -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的介绍到此为止。
案例链接:https://github.com/WQQPsyche/egretProtobuf