Cocos Creator Protobuf的js版本使用

news2024/11/18 15:52:45

一、基础知识

参考

Protocol Buffers 在游戏中的应用

Protobuf语言指南

android与PC,C#与Java 利用protobuf 进行无障碍通讯【Socket】

1.性能好/效率高

现在,俺就来说说Google公司为啥放着好端端的XML不用,非要另起炉灶,重新造轮子。一个根本的原因是XML性能不够好。

• 先说时间开销:XML格式化(序列化)的开销倒还好;但是XML解析(反序列化)的开销就不敢恭维啦。俺之前经常碰到一些时间性能很敏感的场合,由于不堪忍受XML解析的速度,弃之如敝履。

• 再来看空间开销:熟悉XML语法的同学应该知道,XML格式为了有较好的可读性,引入了一些冗余的文本信息。所以空间开销也不是太好(不过这点缺点,俺不常碰到)。

由于Google公司赖以吹嘘的就是它的海量数据和海量处理能力。对于几十万、上百万机器的集群,动不动就是PB级的数据量,哪怕性能稍微提高0.1%也是相当可观滴。所以Google自然无法容忍XML在性能上的明显缺点。再加上Google从来就不缺造轮子的牛人,所以protobuf也就应运而生了。

Google对于性能的偏执,那可是出了名的。所以,俺对于Google搞出来protobuf是非常滴放心,性能上不敢说是最好,但肯定不会太差。

2.代码生成机制

除了性能好,代码生成机制是主要吸引俺的地方。为了说明这个代码生成机制,俺举个例子。

比如有个电子商务的系统(假设用C++实现),其中的模块A需要发送大量的订单信息给模块B,通讯的方式使用socket。

假设订单包括如下属性:

-----------------------

  时间:time(用整数表示)

  客户id:userid(用整数表示)

  交易金额:price(用浮点数表示)

  交易的描述:desc(用字符串表示)

-----------------------

如果使用protobuf实现,首先要写一个proto文件(不妨叫Order.proto),在该文件中添加一个名为"Order"的message结构,用来描述通讯协议中的结构化数据。该文件的内容大致如下:

message Order{required int32 time =1;required int32 userid =2;required float price =3;optional string desc =4;}然后,使用protobuf内置的编译器编译该proto。由于本例子的模块是C++,你可以通过protobuf编译器的命令行参数,指定它生成C++语言的“订单包装类”。(一般来说,一个message结构会生成一个包装类)

然后你使用类似下面的代码来序列化/解析该订单包装类:

// 发送方

Order order;

order.set_time(XXXX);

order.set_userid(123);

order.set_price(100.0f);

order.set_desc("a test order");

string sOrder;

order.SerailzeToString(&sOrder);// 然后调用某种socket的通讯库把序列化之后的字符串发送出去// ......--------------------------------

// 接收方

string sOrder;// 先通过网络通讯库接收到数据,存放到某字符串sOrder// ......

Order order;if(order.ParseFromString(sOrder))// 解析该字符串{

cout <<"userid:"<< order.userid()<< endl

<<"desc:"<< order.desc()<< endl;}else{

cerr <<"parse error!"<< endl;}有了这种代码生成机制,开发人员再也不用吭哧吭哧地编写那些协议解析的代码了(干这种活是典型的吃力不讨好)。

万一将来需求发生变更,要求给订单再增加一个“状态”的属性,那只需要在Order.proto文件中增加一行代码。对于发送方(模块A),只要增加一行设置状态的代码;对于接收方(模块B)只要增加一行读取状态的代码。哇塞,简直太轻松了!

另外,如果通讯双方使用不同的编程语言来实现,使用这种机制可以有效确保两边的模块对于协议的处理是一致的。

顺便跑题一下。从某种意义上讲,可以把proto文件看成是描述通讯协议的规格说明书(或者叫接口规范)。这种伎俩其实老早就有了,搞过微软的COM编程或者接触过CORBA的同学,应该都能从中看到IDL(详细解释看“这里”)的影子。它们的思想是相通滴。

3.支持“向后兼容”和“向前兼容”

还是拿刚才的例子来说事儿。为了叙述方便,俺把增加了“状态”属性的订单协议成为“新版本”;之前的叫“老版本”。

所谓的“向后兼容”(backward compatible),就是说,当模块B升级了之后,它能够正确识别模块A发出的老版本的协议。由于老版本没有“状态”这个属性,在扩充协议时,可以考虑把“状态”属性设置成非必填的,或者给“状态”属性设置一个缺省值

所谓的“向前兼容”(forward compatible),就是说,当模块A升级了之后,模块B能够正常识别模块A发出的新版本的协议。这时候,新增加的“状态”属性会被忽略。

“向后兼容”和“向前兼容”有啥用捏?俺举个例子:当你维护一个很庞大的分布式系统时,由于你无法同时升级所有模块,为了保证在升级过程中,整个系统能够尽可能不受影响,就需要尽量保证通讯协议的“向后兼容”或“向前兼容”。

4.支持多种编程语言

俺开博以来点评的几个开源项目(比如“Sqlite”、“cURL”),都是支持很多种编程语言滴,这次的protobuf也不例外。在Google官方发布的源代码中包含了C++、Java、Python三种语言(正好也是俺最常用的三种,真爽)。如果你平时用的就是这三种语言之一,那就好办了。

假如你想把protobuf用于其它语言,咋办捏?由于Google一呼百应的号召力,开源社区对protobuf响应踊跃,近期冒出很多其它编程语言的版本(比如ActionScript、C#、Lisp、Erlang、Perl、PHP、Ruby等),有些语言还同时搞出了多个开源的项目。具体细节可以参见“这里”。

不过俺有义务提醒一下在座的各位同学。如果你考虑把protobuf用于上述这些语言,一定认真评估对应的开源库。因为这些开源库不是Google官方提供的、而且出来的时间还不长。所以,它们的质量、性能等方面可能还有欠缺。

5.protobuf有啥缺陷?

• 应用不够广

由于protobuf刚公布没多久,相比XML而言,protobuf还属于初出茅庐。因此,在知名度、应用广度等方面都远不如XML。由于这个原因,假如你设计的系统需要提供若干对外的接口给第三方系统调用,俺奉劝你暂时不要考虑protobuf格式。

• 二进制格式导致可读性差

为了提高性能,protobuf采用了二进制格式进行编码。这直接导致了可读性差的问题(严格地说,是没有可读性)。虽然protobuf提供了TextFormat这个工具类(文档在“这里”),但终究无法彻底解决此问题。

可读性差的危害,俺再来举个例子。比如通讯双方如果出现问题,极易导致扯皮(都不承认自己有问题,都说是对方的错)。俺对付扯皮的一个简单方法就是直接抓包并dump成log,能比较容易地看出错误在哪一方。但是protobuf的二进制格式,导致你抓包并直接dump出来的log难以看懂。

• 缺乏自描述

一般来说,XML是自描述的,而protobuf格式则不是。给你一段二进制格式的协议内容,如果不配合相应的proto文件,那简直就像天书一般。

由于“缺乏自描述”,再加上“二进制格式导致可读性差”。所以在配置文件方面,protobuf是肯定无法取代XML的地位滴。

二、proto3 与 proto2

Protobuf 的 proto3 与 proto2 的区别

protobuf一些注意事项

protobuf v3测试

proto3语法

1.在第一行非空白非注释行,必须写:syntax = "proto3";

2.字段规则移除了 “required”,并把 “optional” 改名为 “singular”

3.默认值:

• string类型默认值是空字符串,不是null

• bytes类型默认是空bytes

• bool类型默认值是false

• 数字类型默认值是0

• 枚举类型默认值是第一个枚举值,即0

• repeated修饰的字段,默认值是空(在对应的编程语言中通常是一个空的list)

三、js中使用

1.注意现在有两个版本,cocos论坛讨论里,推荐decodeio的protobufjs

参考

Node.js使用google-protobuf

cocos creator中使用protobuf(dcodeIO/protobuf.js 5.0)

这里网上查阅资料可能会让人混乱,其实是因为在google官方的js库出来之前,decodeio先推出了一个库叫protobufjs。

随着Google的Protobuf3的发布,Google终于开发了一个可以给JavaScript使用的库。之前大家如果在node端使用了Protobuf应该用的是protobufjs这个库,但是既然Google官方支持了JavaScript,那么我们还是要去尝试一下的。

主要存在两个解决方案 使用protobufjs 或者 谷歌官方的js解析(通过protoc.exe生成.proto对应的js文件直接使用),个人认为protojs更为方便,如果更改.proto文件都要使用protoc重新生成对应的js文件略为繁琐。所以这里我们直接采用的protobufjs。

区别很简单,如果用protoc --js_out这种,就是官方的库。如果直接加载proto文件去解析,或者pbjs导出的,就是decodeio的库了。

2.官方的https://github.com/protocolbuffers/protobuf/tree/master/js

• 安装方式:npm install google-protobuf

• 生成文件:protoc ./test.proto --js_out=import_style=commonjs,binary:.

这里有两种形式,一种是common.js,一种是closure(google style).common.js生成的js要使用 require命令导入,closuer.js生成的js要使用goo.provide命令来导入。

• 用例:

前端后台以及游戏中使用Google Protocol Buffer详解

解决方案:在Cocos Creator1.8中使用官方的google protobuf

3.decodeio的https://github.com/protobufjs/protobuf.js

• 安装方式:npm install protobufjs

• 生成文件:pbjs -t static-module -w commonjs -o compiled.js file1.proto file2.proto

• 用例:cocos creator中使用protobuf(dcodeIO/protobuf.js 5.0)

• 注意事项:在 creator 与protobuf的那些事提到了版本问题:大佬们写的教程基本都是 基于protobuf5 也是他们说的直接在项目下面 npm install protobufjs 但是npm下来的却是protobuf最新的版本,所以你们想学习大佬的教程一定要npm install protobufjs@5 这样才行,不然你就只能看着大佬的教程干瞪眼了。

ProtoBuf.js同时支持NodeJS和Browser,也就是说,现在我们可以在JS client端使用protobuf!当然,前提是我们使用的是高级浏览器,因为ProtoBuf.js依赖于ByteBuffer.js(一个对ArrayBuffer进行了封装的类库),所以,只能say byebye to IE < 10。

由于 JavaScript 精度问题,所以 int64和 uint64等类型数据会被转换成 Long.js 对象实例,Long 并不太复杂,与 bignumber.js 类似,具体参考 Long.js API.

四、WebSocket断粘包

websocket也是基于tcp的,相当于在tcp基础上封装了一层。 某种程度来说tcp的性能优于websocket,因为websocket就是在tcp的基础上多了一层转化,但是websocket使用更简单,用tcp的app端需要自己去读tcp流,根据包头和包体组装数据包,而websocket不需要,因为websocket会是一个整包的数据并不是流的形式。 具体来说,后端通过缓存区把数据冲刷(flush)给前端,app端拿到tcp数据流,需要根据消息头给定的消息体长度,去拿取后面多少位的数据,然后组装成一个数据包。 而websocket传输过来就是一个个的包,也就是帧并不是数据流,所以后端在给websocket数据的时候,必须要把一个整包,在缓冲区一次性冲刷过来,而给tcp的话就可以自由冲刷。

也就是说如果服务端同样采用的是websocket的话(Node.js及 ws库),我们对消息是不需要添加数据头进行数据包的组装的。websocket是按照包一次性读取的。既我们不需要在手动的定义数据包头以及添加数据包长度信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10.0、Linux-磁盘管理简单初体验

10.0、Linux-磁盘管理简单初体验 列出文件系统整体的磁盘使用量 -> df -h ( 检查磁盘空间使用量 ) 查看目录中所有的文件磁盘空间使用情况 -> du -a -h 根目录下每个目录所占空间大小容量 -> du -sm /* Mac 或者想使用 Linux 挂载我们的一些本地磁盘或者文件 挂载&am…

时隔 20 年,这个编程语言再次“称王”!

↓推荐关注↓综合整理&#xff1a;程序员的那些事&#xff08;id: iProgrammer&#xff09;近日&#xff0c;全球知名的编程语言流行度排行榜网站 TIOBE 公布了 1 月编程指数信息。前三的编程语言是Python、C 和C&#xff0c;第四为Java&#xff0c;第五是C#。TIOBE 的 2022 年…

MyBatis#1(快速入门与Mapper代理)

一.MyBatis简介1.MyBatis是一款优秀的持久层框架,可用于简化JDBC的开发2.持久层: 负责将数据保存到数据库的那一层代码JavaEE的三层架构: 表现层, 业务层, 持久层3.框架:框架就是一个半成品软件, 是一套可重用的, 通用的, 软件基础代码模型优点: 高效, 规范, 通用, 可扩展二.My…

ESP32设备驱动-BMP180气压温度传感器驱动

BMP180气压温度传感器驱动 1、BMP180介绍 BMP180 是Bosch Sensortec 新推出的数字气压传感器,性能非常高,可用于智能手机,平板电脑和运动设备等高级移动设备。它遵循BMP085并带来许多改进,如较小的尺寸和数字接口的扩展。超低功耗低至3μA,使BMP180成为移动设备节能的领…

EfficientFormer: Vision Transformers at MobileNet Speed

Paper name EfficientFormer: Vision Transformers at MobileNet Speed Paper Reading Note URL: https://arxiv.org/pdf/2206.01191.pdf TL;DR 本文目标是回答一个问题&#xff1a;transformer 是否可以在比 cnn 运行更快的时候同时精度更高&#xff1f;本文提出了 Effic…

3. R获取数据的三种途径、读入文件、写入文件、读写excel文件、读写R文件

课程视频链接&#xff1a;https://www.bilibili.com/video/BV19x411X7C6?p1 本笔记参照该视频&#xff0c;笔记顺序做了些调整【个人感觉逻辑顺畅】&#xff0c;并删掉一些不重要的内容 系列笔记目录【持续更新】&#xff1a;https://blog.csdn.net/weixin_42214698/category_…

后端人眼中的Vue(三)

五、高级 5.1、计算 5.1.1、computed ​ 在之前的购物车的案例当中&#xff0c;我们已经实现了购物车价格的计算&#xff0c;但是有些时候我们需要在其他很多地方也展示价格&#xff0c;所以每展示一次&#xff0c;我们就需要调用一次计算价格的方法&#xff0c;所以Vue给了…

OV7670 摄像头模块介绍

OV7670摄像头模块简介OV7670是OV&#xff08;OmniVision&#xff09;公司生产的一颗1/6寸的CMOSVGA图像传感器。该传感器体积小、工作电压低&#xff0c;提供单片VGA摄像头和影像处理器的所有功能。通过SCCB总线控制&#xff0c;可以输出整帧、子采样、取窗口等方式的各种分辨率…

Visio 学习笔记 —— Visio 的键盘快捷方式

Visio 学习笔记 —— Visio 的键盘快捷方式常用热键常用对话框文本操作快速访问工具栏参考资料常用热键 操作热键指针工具Ctrl 1文本工具Ctrl 2连接线Ctrl 3连接点工具Ctrl Shift 1裁剪工具Ctrl Shift 2文本块工具Ctrl Shift 4组合所选的形状Ctrl G解散组合Ctrl Sh…

Verilog语法笔记(夏宇闻第三版)-结构说明语句

目录 initial语句&#xff1a; always语句&#xff1a; task和function说明语句&#xff1a; task和function说明语句的不同点&#xff1a; task说明语句&#xff1a; function说明语句&#xff1a; Verilog语言中的任何过程模块都从属于以下四种结构的说明语句&#xff…

【GNN】图基本知识代码、nxworks包的基本使用

一个写得很好的博客&#xff1a; 图或网络中的中心性&#xff1a;点度中心性、中介中心性、接近中心性、特征向量中心性、PageRank 特征向量中心性&#xff08;eigenvector centrality&#xff09; 特征向量中心性的基本思想是&#xff0c;一个节点的中心性是相邻节点中心性的函…

Reactive思考

最近在学习响应式编程&#xff0c;由此翻看了很多资料&#xff0c;在此把思考过程记录下 目录 来由 规范 具体实现 历史 1. Servlet的尝试 1.1 Async实现demo 2. web应用层 2.1 web-flux 2.2 web-flux/web-mvc 与 spring-web架构关系 3. DBConnection层 相关可能混淆…

STL中vector怎么扩容

STL vector扩容 vector容器 vector被称为向量容器&#xff0c;该容器擅长在尾部插入或删除元素&#xff0c;时间复杂度为O(1)&#xff1b;而对于在vector容器头部或者中部插入或删除元素&#xff0c;则花费时间要长一些&#xff08;移动元素需要耗费时间&#xff09;&#xf…

十九、Kubernetes中Pod调度第一篇

1、概述 在默认情况下&#xff0c;一个Pod在哪个Node节点上运行&#xff0c;是由Scheduler组件采用相应的算法计算出来的&#xff0c;这个过程是不受人工控制的。但是在实际使用中&#xff0c;这并不满足的需求&#xff0c;因为很多情况下&#xff0c;我们想控制某些Pod到达某些…

Gradle学习笔记之插件

文章目录插件的作用插件的分类和使用脚本插件对象插件第三方插件用户自定义插件buildSrc项目编写步骤其他项目/模块引用步骤java插件常用属性插件的作用 插件可以帮助我们促进代码的重用、项目更高程度的模块化、自动化和便捷化&#xff0c;减少功能类似代码的编写&#xff0c…

【数据结构与算法】 | 用队列实现栈

用队列实现栈 链接&#xff1a; https://leetcode.cn/problems/implement-stack-using-queues/ 1. 要求 2. 思路 栈的性质是先进后出&#xff0c;队列的性质是先进先出。 题目要求是用两个队列来完成栈的实现&#xff0c;那么大思路就是通过倒腾数据来完成。 3. 代码实现…

JAVA系列 多线程 Thread类 耦合 线程调度 如何创建线程 弱耦合 完全解耦 思维结构整理

这估计是我JAVA系列 基础知识点梳理的最后一篇文章了吧 之后一段时间 我打算去看看之前承诺更新的JAVA的一些项目了 然后我要好好玩一段时间游戏 然后跟某些好朋友见面 所以后面会忙一点 然后就是很多同学 六级还没有考 估计很多人是开学再考把 这个假期就不要玩的太厉害了 没事…

人员超员识别系统 yolov5

人员超员识别系统通过yolov5深度学习网络模型对现场画面进行实时监测&#xff0c;监测到画面中区域人数超过规定人数时&#xff0c;立即抓拍存档预警。YOLO系列算法是一类典型的one-stage目标检测算法&#xff0c;其利用anchor box将分类与目标定位的回归问题结合起来&#xff…

一篇彻底解决:Fatal error compiling: 无效的目标发行版: 11 -> [Help 1]

先在这声明,如果我的方法没有解决你的问题,那你直接私信我,我第一时间帮你解决,送佛送到西!!! 这个问题&#xff0c;主要原因就是JDK的版本问题&#xff0c;“无效的目标发行版&#xff1a;11”的意思是你在某个位置配置了JDK11&#xff0c;但是在其他位置配置的并不是11&…

靶机测试Gears of War笔记

靶机介绍Its a CTF machine that deals with the history of gears of war, where we must try to escape from prison and obtain root privileges. it has some rabbit holes, so you have to try to connect the tracks to get access.This works better with VirtualBox ra…