参考:

CSDN:Egret项目中使用protobuf(protobufjs)

TS项目中使用Protobuf的解决方案(babel)

在cocos creator中使用protobufjs

layabox:网络和格式--ProtocolBuffer

egret protobuf(egret官方提供的工具,自动配置和生成)

 

目录
一 protobuf简介
二 使用protobuf
三 将.proto文件转成js和d.ts

四 精简生成文件

五 demo下载

六 Protobuf为什么快


一 protobuf简介
百度百科:protocolbuffer(以下简称PB)是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了多种语言的实现:java、c#c++、go 和 python,每一种实现都包含了相应语言的编译器以及库文件。由于它是一种二进制的格式,比使用xml 进行数据交换快许多。可以把它用于分布式应用之间的数据通信或者异构环境下的数据交换。作为一种效率和兼容性都很优秀的二进制数据传输格式,可以用于诸如网络传输、配置文件、数据存储等诸多领域。

参考:protocol buffer_百度百科  中重度游戏开发框架:EGER PRO开发教程
google_protobuf数据类型      


二 使用protobuf
1  导入第三方库
我直接把protobuf第三方库放在了项目中..
 

修改egretProperties.json文件,增加protobuf库。添加完成后,需要编译引擎。
 

2 编写protobuf文件
新建一个文件template.proto
我这里编写一个测试用数据,user_login
 

3 加载protobuf文件

注意类型要是text
 

4 使用protobuf
读取template_proto文件

[C++] 纯文本查看 复制代码
1
var message = dcodeIO.ProtoBuf.loadProto(RES.getRes("template_proto"));



新建一个user_login类

[AppleScript] 纯文本查看 复制代码
1
2
3
4
var user_login_class = message.build("user_login");
var user_login = new user_login_class();
user_login.userId = 123;
user_login.userName = "peter";



将user_login转成字节

[C#] 纯文本查看 复制代码
1
var bytes = user_login.toArrayBuffer();



socket发送user_login

[C#] 纯文本查看 复制代码
1
2
3
var socket:egret.WebSocket = new egret.WebSocket();
socket.writeBytes(bytes);
socket.flush();



接收数据的处理

//接收服务端数据(假设byteArray是服务端websocket接收数据)
var revData:egret.ByteArray = byteArray;
       
//读取数据
 var user_login = user_login_class.decode(revData.buffer);
console.log("接收数据:", user_login);

  


三 将.proto文件转成js和d.ts

怎么自动将.proto文件导出成ts文件?有没有现成工具?

比如一个.proto文件里有

message user_login{
    required int32 userId = 1;
    required string userName = 2;
}

message user_login2{
    required int32 userId = 1;
    required string userName = 2;
}

怎么导出js的文件,在egret中直接使用

class user_login{
     public userId:number;
     public userName:string;  
}

class user_login2{
     public userId:number;
     public userName:string;  
}

 

protobufjs工具

protobufjs是一个npm包,可以将.proto转成js和d.ts文件,然后egret中可以将js和d.ts当作第三方库使用,直接在代码中用new创建.proto中的数据并且还有代码提示。

准备一个测试用的.proto文件

 

在安装了nodejs的情况下,全局安装protobufjs。打开cmd窗口,输入:

npm install protobufjs -g

 

然后在你的proto文件的目录下,打开cmd窗口

输入:

pbjs -t static-module -w commonjs -o template.js template.proto
pbts -o template.d.ts template.js 

 

 得到如下文件:

 

仅仅是一些测试数据,文件有80kb+。

 

 

生成的文件还有问题。参考:Babel 入门教程

 

egret官方提供的工具

egert官方提供的工具是封装了protobufjs,并且在此基础上增加了功能,例如可以修改配置精简文件大小,可以直接将.proto文件转成js和d.ts到指定egret项目文件夹下。

下载官方demo,得到如下文件。

dist                                     存放了protobuf-library.js库

egret-project                      白鹭项目

egret-project_wxgame      白鹭小游戏项目

out                                     存放cli.js、index.js,用于拷贝protobuf源码到白鹭项目,添加protobuf到egretProperties.json配置文件中等等

src                                     存放index.ts

.gitignore                           忽略文件

package.json、tsconfig.json    其他等等配置文件

 

 

根据教程尝试安装。全局安装protobufjs。

npm install protobufjs@6.8.4 -g
npm install @egret/protobuf -g

 

 在你的白鹭项目下,打开cmd窗口,输入pb-egret add,将代码和项目结构拷贝至白鹭项目中

pb-egret add

譬如我的白鹭项目是TTT

这是会项目目录下会新增一些文件,配置文件也会自动被修改

 

将测试用的.proto文件放在项目目录TTT\protobuf\protofile下

 

.proto一定要有package 

 

cmd中输入pb-egret generate,文件将会生成到 protobuf/bundles 文件夹中

pb-egret generate

 

生成的文件如下。这是.proto文件转成的js库,已经自动配置到egretProperties.json中了。

 

 代码中使用(未实际测试)

        //create user_login
        let sendData = new template.user_login();
        sendData.userId = 1;
        sendData.userName = "abc";
        
        //encode user_login
        let sendByte = template.user_login.encode(sendData).finish();

        //websocket send
        let byteArray:egret.ByteArray = new egret.ByteArray(sendByte);
        let socket:egret.WebSocket = new egret.WebSocket();
        socket.writeBytes(byteArray);
        socket.flush();

        //decode user_login
        let user_login = template.user_login.decode(sendByte);
        console.log(user_login.userId,  user_login.userName);  //输出1 "abc"

 

我们打开protobuf-bundles.js,会发现user_login里有有以下方法

create

encode

encodeDelimited

decode

decodeDelimited

fromObject

toObject

toJSON

verify

convert

我们可以对该生成规则进行精简,在生成js文件时,生成指定的方法,减少文件大小

 

四 精简生成文件

1、首先修改out文件夹下的index.js

讲generate下的case14修改如下

 

2、再修改项目protobuf文件夹下的pbconfig.json

 修改如下

3、再次打开cmd窗口pb-egret generate生成一次proto文件

会发现create,verify、convert、delimited方法没有了。

 

4、关于protobuf-bundles.js中的注释,则无需精简,再发布项目时,会自动压缩去掉这些注释。

 

 

五 demo下载

https://files-cdn.cnblogs.com/files/gamedaybyday/Egret3.2.6_ProtobufExample.7z

 

六 Protobuf为什么快

网上搜到的:

1.压缩率高:Protobuf基于接口描述语言IDL(Interface Description Language)实现消息结构的定义,传输数据的两端都需要定义该消息结构,并保存在.proto文件中,这样就不需要在消息数据中定义结构信息,自然就把空间压榨到极限了。
2.编码效率高:Protobuf采用二进制编码方式,相比于文本编码(如JSON、XML等),二进制编码在数据传输时更加紧凑,减少了数据传输量。同时,Protobuf采用变长编码和稀疏字段技术,可以有效地降低编码复杂度和处理时间。
3.内存优化:Protobuf对内存的使用进行了优化,通过使用内存映射文件等技术,可以有效地降低内存消耗,提高内存利用率。
4.多语言支持:Protobuf支持多种编程语言,如C++、Java、Python等。这使得开发人员可以使用自己熟悉的编程语言来编写代码,减少了开发和维护的成本。
5.良好的扩展性:Protobuf支持自定义数据类型和消息类型,可以根据实际需要扩展其功能。

 

大概解释下:

压缩率高:因为客户端和服务端都有.proto文件,文件里已经定义了数据结构,所以客户端和服务端通讯只需要结构信息和值就行了,光这一点就大大减少了数据量。

例如下面数据

message helloworld
{
    required int32 id = 1;
    required string str = 2;
    optional int32 wow = 3;
}

 

tag:结构信息,最低三位wire_type表示字段类型,三位以上field_number表示哪个字段。

field_number:表示第几个字段,例如id第1个字段,str第2个字段。因为字段类型wire_type有0-5,需要占3位,所以field_number需要左移3位。

wire_type:字段类型。

tag = (field_number << 3) | wire_type;

 

编码率高:采用可变长度编码Varint,例如4字节的int型,当数字例如只有10比较小时,可能只需要传送1字节就行了。

 

这是别人做的效率对比  IM通讯协议专题学习(五):Protobuf到底比JSON快几倍?全方位实测

 

posted on 2018-06-24 11:18  gamedaybyday  阅读(11100)  评论(0编辑  收藏  举报