ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。
下载地址:http://download.csdn.net/download/yue19870813/9957415
解压后包括如下几个文件:
- ByteBufferAB.min.js
- Long.min.js
- protobuf.d.json
- protobuf.d.ts
- ProtoBuf.min.js
白鹭官方第三方库使用文档:http://developer.egret.com/cn/github/egret-docs/extension/threes/instructions/index.html
当我们准备好了要用的第三方库的源文件后,还需要把它编译成 egret 需要用的第三方库。以我们上面下载的protobuf文件为例。
- 创建一个egret第三方库的项目文件,在命令行中输入:
egret create_lib protobuf
注意:第三方库项目与 Egret 项目不能嵌套。请不要在Egret 项目目录下面创建第三方库项目。
{
"name": "egret",
"version": "3.0.8",
"modules": [
{
"name": "protobuf",
"description": "protobuf",
"files": [
"Long.min.js",
"ByteBufferAB.min.js",
"ProtoBuf.min.js",
"protobuf.d.ts"
],
"root": "src"
}
]
}
egret build protobuf
和官方的模块使用方式相同,在egretProperties.json中配置:
{
"native": {
"path_ignore": []
},
"publish": {
"web": 0,
"native": 1
},
"egret_version": "4.0.1",
"modules": [
{
"name": "egret"
},
{
"name": "socket"
},
{
//第三方库的名称
"name": "protobuf",
//刚才我们创建的第三方库的路径,绝对路径或者相对路径
"path": "../protobuf"
}
]
}
重新编译项目,如果没有报错,正常情况下protobuf库就算是引用到了项目中,后面就可以直接使用了。
关于protobuf消息定义的详细介绍:http://www.jianshu.com/p/b1f18240f0c7
我们这里定义两个结构体,一个用于向服务器发送消息,另一个用于接收消息来解析。
//向服务器发送的消息
message SendMsg {
required uint32 id = 1; //int类型
required string name = 2; //字符串类型
}
//服务器发送的消息,我们会用protobuf来解析
message BackMsg {
required uint32 type = 1; //int类型
required SendMsg back = 2; //返回一个结构体数组
}
//在protobuf的消息定义中支持消息嵌套,详细的定义方式参照上面发的连接。
//初始化消息体
var builder:any = dcodeIO.ProtoBuf.loadProto("上一步声明的消息结构文本");
//构建SendMsg协议对象
var clazz = builder.build("SendMsg");
var data = new clazz();
var arraybuffer:ArrayBuffer = data.toArrayBuffer();
var buf = new egret.ByteArray(arraybuffer);
//创建ByteArray数组用来保存消息对象并发送到网络
var mss = new egret.ByteArray();
//写入消息体
mss.writeBytes(buf);
//创建websocket对象
var ws = new Websocket(); //此行为伪代码
//将消息写到服务器
ws.writeBytes(mss);
//socket接收的数据(_socket是前置已经连接的)
let btyearray: egret.ByteArray = new egret.ByteArray();
this._socket.readBytes(btyearray);
this._onReceive && this._onReceive(btyearray);
//读取服务器发送过来的字节数据
let msgBuff: ArrayBuffer;
let barr: egret.ByteArray = new egret.ByteArray();
btyearray.readBytes(barr);
let len = barr.buffer.byteLength;
let dataView = new DataView(barr.buffer);
let pbView = new DataView(new ArrayBuffer(len));
for (let i = 0;i < len;i++) {
pbView.setInt8(i,dataView.getInt8(i));
}
msgBuff = pbView.buffer;
//解析消息内容
var builder:any = dcodeIO.ProtoBuf.loadProto("上一步声明的消息结构文本");
var clazz = builder.build("BackMsg");
var data = clazz.decode(msgBuff);
//获取数值
var type = data.get("type");
var smsg = data.get("back");
var id = smsg.id;
var name = smsg.name;
这样做之后发现,使用protobuf后还是有些不方便,还是要手动写很多解析代码,这里我们可以将上面两步的内容工具话,代码自动生成,下面就把一个用Python写的一个代码生成脚本贡献出来,其中还包括了服务端用的java代码生成。
下载地址是:http://download.csdn.net/download/yue19870813/9959227
// SendMsg
class SendMsgMessage extends MessageBase {
private _data:any = null;
private _clazz:any = null;
public constructor() {
super();
var builder:any = dcodeIO.ProtoBuf.
loadProto("消息定义文本内容");
this._clazz = builder.build("SendMsg");
}
public setId(id:any):void {
this._data.set("id", id);
}
public getId():any {
return this._data.get("id");
}
public setName(name:any):void {
this._data.set("name", name);
}
public getName():any {
return this._data.get("name");
}
public getPID():number {
return 3001;
}
public initData():void {
this._data = new this._clazz();
}
public setData(buff:egret.ByteArray):void {
this._data = this._clazz.decode(buff);
}
public toByteArray():egret.ByteArray {
var arraybuffer: ArrayBuffer = this._data.toArrayBuffer();
return new egret.ByteArray(arraybuffer);
}
}
// BackMsg
class BackMsgMessage extends MessageBase {
private _data:any = null;
private _clazz:any = null;
public constructor() {
super();
var builder:any = dcodeIO.ProtoBuf.
loadProto("消息定义文本内容");
this._clazz = builder.build("BackMsg");
}
public setType(type:any):void {
this._data.set("type", type);
}
public getType():any {
return this._data.get("type");
}
public setBack(back:any):void {
this._data.set("back", back);
}
public getBack():any {
return this._data.get("back");
}
public getPID():number {
return 3002;
}
public initData():void {
this._data = new this._clazz();
}
public setData(buff:egret.ByteArray):void {
this._data = this._clazz.decode(buff);
}
public toByteArray():egret.ByteArray {
var arraybuffer: ArrayBuffer = this._data.toArrayBuffer();
return new egret.ByteArray(arraybuffer);
}
}
//创建消息协议
var sendMsg = new SendMsgMessage();
sendMsg.initData();
sendMsg.setId(1);
sendMsg.setName("Tim");
var sendBuf = sendMsg.toByteArray();
//可以通过websocket或者http发送sendBuf到服务器。
//解析消息时
var backBuf; //假设这是服务器返回的数据
var backMsg = new BackMsgMessage();
backMsg.setData(backBuf);
var type = backMsg.getType();
var back = backMsg.getBack();
var id = back.getId();
var name = back.getName();
//_no_cache : 不做缓存
//_c_noNeed :不需要生成ts代码
这两中标签使用会在后续完整工作流中介绍。
本文仅结束了protobuf对象的创建和使用及工具化。但这套生成的机制预留了很多接口和标签后续会针对这些有一套完整的通信协议的工作流在项目中使用。大家可以持续关注。
如果对我的文章感兴趣可以关注我的公众号: