BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Flash务实主义(八)——减少数据传输量

| 作者 flashyiyi 关注 0 他的粉丝 发布于 2011年6月26日. 估计阅读时间: 6 分钟 | GMTC大前端的下一站,PWA、Web框架、Node等最新最热的大前端话题邀你一起共同探讨。

举个简单的例子,我们要显示一个背包中的道具,需要道具数据库保存ID、类型ID、图片地址、名称、大类别、子类别、质量、说明、是否出售、是否锁定、道具创建时间、道具持续时间、使用效果定义字符串、可使用等级、堆叠数量、最大堆叠数、出售单价等等,如果按传统做法,就是返回一个二维数组,将所有信息加载进来,然后直接填充列表,依次填写各项内容。这个做法很很简单,初级程序员就能完成,但代价是,传输数据量会非常大。

下面介绍的内容就是为了缩小数据量,较少传输时间及降低服务器压力。

传输数据格式

现在常见的传输数据格式有三种:XML,JSON,AMF。

XML是通用数据格式,在保存数据方面有明显优势,在传输数据方面,对Flash而言,数据传输的双方都是确定的,并不需要通用,所以XML这点优势不突出。因此,实际可用的就是体积较小的JSON和AMF这两种格式。前者可以用Firebug直接查看数据,后者目前也有很多方法可以查看数据了。同样数据内容,JSON即使压缩也应该比AMF的体积大,但AMF由于协议负责会有固定额外体积,如果只传一个数据JSON反而会比较小。

一般情况下,选AMF更好,不过即使用JSON应该也不会有太多性能问题,旧项目无需强求。

存储数据格式

在游戏中通常可以看到,道具栏可能会有同种道具多次出现。这时候重复加载数据是一种浪费。通常一款游戏道具数量不过数百个,即使包含大量描述信息,全部用XML保存,最多也就几百KB(千字节),用G-ZIP(即ByteArray的compress()方法)压缩后可达几十KB,这不过相当于一张大图而已,与整体资源体积相比只是个零头。所以即使作为资源一次加载也是没问题的。

这样我们可以将所有道具固定信息保存在一个文件中,开始便加载,在加载完后取出所有数据。这些数据是道具定义,包含类型ID、图片地址、名称、大类别、子类别、质量、说明、是否出售、是否锁定、使用效果定义字符串、可使用等级、最大堆叠数量、出售单价。这些信息的保存形式可以是XML、JSON、AMF,具体形式无所谓。服务端只需要返回数据库中保存的唯一标识ID、类型ID、堆叠数量这三个值就可以,然后通过类型ID找到道具定义中其他需要的数据。

显然这笔之前传输的数据量要少很多。

三种存储形式各有特点:XML优点在于格式通用,很多软件都能修改及输出,且容易被Flash解析;JSONG也容易被Flash解析,体积较XML小,但支持的软件少,需要自己写编辑工具或转换工具;AMF体积更小,但因为不是文本形式,不用专门工具无法修改,是最依赖工具的格式。

由于这部分分数据体积不大,不需要过于纠结保存的格式。个人比较推荐XML格式,这样完全不依赖特殊工具,数据库也容易自动生成,是目前网页游戏及客户端游戏广发使用的。(星际争霸2就包含了大量XML)

文本文件压缩方法

上面提到的G-ZIP压缩指的是ByteArray的compress()方法,将文本写入ByteArray,执行compress()方法保存成文档,读取时获得ByteArray,执行uncompress()获得文本。

一般一个有格式描述的XML文件可以压缩到1/10,所以文本文件体积不是问题。可以用这个工具来实现压缩及解压文本文件:

http://code.google.com/p/ghostcat/source/browse/trunk/tools/GhostCatTool.swf

这里有个小技巧,当ByteArray未被压缩时,执行uncompress()会出错但不会改变ByteArray的内容,因此可以用try捕获uncompress()方法引发的错误,无论成功与否都获得数据。这样如果加载未压缩文件也可以正常使用,在调试时使用未压缩文件也方便修改,发布时再生成压缩版本以减小体积。

仅更新修改

当你使用了一个道具后,该如何更新物品列表呢?发出使用请求后重新加载道具列表?这是最简单也最浪费的做法,原因应该无需说明。

这就要求我们应用模型和视图分离的思想。获得整个道具列表后将数据保存在他处,即使关闭面板数据也还存在。之后直接操作这个保存的数据。使用道具就减少道具堆叠数量,数量为0时就删除这个道具,同时发送给服务端使用道具请求。不重复获取整个列表,而是与服务端一直同时修改列表。虽然出现Bug时会造成前后端不一致,但这种做法是值得推荐的。

获得道具也是同样原理,应该获取新道具信息,并将数据添加到道具模型中。每次都重新加载列表确实很简单很稳定,但做法过于粗糙和暴力。

减少键值数据

当传送大量数据(诸如500个好友)时,即使只传输必要数据,数据量也可能会很大。当然这要看采用哪种传输数据格式,不管用哪种格式都会有数据冗余——那就是对象的键。当传输的数据是数组时,数组里是同样类型的对象,但即使都是同样类型,序列化时依然要在每个对象里重复传递对象的每个键字符串。如果有500条数据,这些键字符串就会重复500次。

把对象转换成数组,就可以不传递这个键值,数据体积将会大大减小,也可以单独将键值传过去,方便完成传输后重新组合成对象。

二进制协议

最彻底的解决方案是采用规定的二进制协议来传输数据。将数据根据特定的格式和顺序依次存入ByteArray中,定长数据直接保存,而不定长数据则先保存长度再保存数据(数组也是不定长数据的一种),这样生成BytesArray,直接发送到另一边,再用同样的方法将数据取出来。这样做数据量最少,但是二进制协议的开发成本相对比较高,也容易出错,因此只在对即时通讯要求较高的情况下使用。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

说起来最近json已经as原生解析了 by withyou gakaki

protobuffer vs messagepack vs amf

轮回 by phonix cao

好不容易从二进制协议演化为xml格式,这文档的最终解决方案居然还会是建议二进制协议....

Re: 轮回 by 小 龙

在数据量密集的实时WebGame中,二进制传输的数据两可以被压缩到XML的30%左右,这个对于动态流量费用每月动轧几百万的运营成本来说,还是十分值得做的,而且你也不要求全部的命令都使用二进制,只要针对某些特别密集发送的命令做一个特殊处理就好了。

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

3 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT