精华内容
下载资源
问答
  • 目前该论坛主要为51页游事业部内部举行每周一期的技术沙龙提供一个资源共享和讨论的平台,通过在该平台的讨论和课件共享来见证51大家庭的共同进步,当然将这些资源对外开放也是作为一家互联网企业支持开源,鼓励共享...
  • 最后发现主要是玩抢车位之类的游戏,当然还有很多类似的WebGame,给我的感觉是WebGame现在已无处不在。    记得前几年以博客、视频、社区为代表的WEB2.0风潮逐渐席卷整个中国互联网行业以来,“创新”和“互动”这...

           之前不怎么上校内,但最近很多同事喜欢泡校内,我好奇的去看了下他们在干嘛?难道是写博客?最后发现主要是玩抢车位之类的游戏,当然还有很多类似的WebGame,给我的感觉是WebGame现在已无处不在。

     

          记得前几年以博客、视频、社区为代表的WEB2.0风潮逐渐席卷整个中国互联网行业以来,“创新”和“互动”这两个概念已经成为互联网发展必不可少的因素。无数新型社区网站也开始风潮涌动。但是缺少成熟的商业模式、缺乏直接的赢利点,这让许多社区类的互联网企业面临生死的考验。WebGame犹如一支强心剂,让互联网企业继网络游戏、无线增值、电子商务、网络营销之后又看到了一种新的盈利希望,特别是为有着高粘着度、商业模式却不明朗的SNS社区带来了盈利新模式。

     

          在大型的客户端网游兴起之前,正真意义上的WebGame从文字MUD的废墟上开始发芽,当年在网络泡沫经济的推动下,国内涌现了不少规模较大的WebGame.例如《第九城市》、《逸飞岭》等,以及活跃在各信息港的不同版本的《笑傲江湖》。它们是国内第一批基于Web浏览器而产生的WebGame。对于这些WebGame,玩家不需要投入大量时间与精力,不需要每天重复着枯燥打怪练级,很快就在玩家群体得到了很大反响。《天空左岸》等早一批上线的WebGame得到空前成功,也为后来者成功开辟整体市场环境和道路。于是很多研发商以及运营商都开始涉足WebGame市场,试图在早期时候能迅速占领市场,并且能快速盈利或者满足其他条件。但是新市场里除了充满了机遇之外,同样也潜藏着更多挑战。


          对于产品研发,WebGame不同于网络游戏或者大型的单机游戏,研发周期相对短的多,而且其他方面的成本也比较小,几个人的小团队基本上几个月就能开发出一款游戏。这是WebGame优势,也可以说是WebGame劣势。门槛的降低,使得很多人都能参与到行业竞争中,对于扩大行业市场有很大帮助,但是也很容易造成行业内产品质量参差不齐,恶性竞争等问题。当然新兴行业总是会有这样或那样问题,只有经过实践与失败积累,行业才能得到更为长足发展。如果在很长时间内,不能解决这些问题,带来可能是整个行业崩溃。

     

    展开全文
  • webgame架构

    2019-09-30 15:53:06
    今天在JAVAEYE中看了到了一篇关于webgame的文章,记录下来!以备以后用!1 体系结构 1.1 传统的网站的架构 传统的网站一般都是以N层结构一般N为3,就是我们常说的三层架构。 3层架构分为数据层、业务逻辑层、页面...

    今天在JAVAEYE中看了到了一篇关于webgame的文章,记录下来!以备以后用!

    1 体系结构
    1.1 传统的网站的架构
    传统的网站一般都是以N层结构一般N为3,就是我们常说的三层架构。
    3层架构分为数据层、业务逻辑层、页面显示层。
    1.2 WebGame的架构
    WebGame可以看作是网站和游戏的结合体,因此它具备了这两类系统的特性。我们不但可以把WebGame看作是一个网站,也可以把它看作是一个网络游戏。
    的网站是B/S结构,网络游戏则是C/S结构,WebGame则是这两者的结合我们暂且称之为B/C/S结构。既在用户眼里,它是一个通过浏览器范围的网站。在服务器系统里,它又是一个传统的C/S结构的网络游戏。

    从 上图分析,用户通过浏览器访问服务器的时候,首先是访问网页服务器,如windows平台下的IIS,linux下的Apache。在通过网页服务器,以 某种特殊的方式(分布式访问,如.net下的remoting)去访问游戏服务器,通知游戏逻辑服务器执行玩家操作,并从游戏逻辑服务器里获得游戏相关的 信息,或者直接通过访问数据库而获得游戏数据。

    1.2.1 为什么要将服务器分为游戏服务器和网页服务器
    网页服务器的特点是 触发执行,及当有用户访问网页的时候,才会执行该网页的程序代码。而我们常见的WebGame(Ogame,Travian)这些游戏实际上是需要24小 时不间断执行的,因此网页服务器的执行方式并不适合与游戏。因此我们另外需要一个应用程序来执行这些24小时不间断要做的事情。这也就是我们需要增加一个 游戏服务器的原因。
    Webgame现在已经开始需要进入大统一服务器时代,每个游戏区域容纳的玩家数量将从现在的几万人发展到几十万人,因此在 新的背景下,webgame如何处理大量用户的请求将成为问题。目前一台asp.net做的weggame服务器每秒能处理500~1000个页面请求, 按照每个玩家每隔3~5秒做一次页面操作(页面请求),一台服务器能承受2k~4k的玩家在线,对于一个只有几万人的策略游戏来说,已经是足够了。但对于 一个未来将承载几十万人的游戏来说远远不够。

    通过分析,玩家在游戏过程中,有80%以上的访问仅仅只是查看玩家在游戏里的状态,实际上 真正会对游戏运行状态及数据修改的的页面请求不足20%。因此,我们可以将呈现页面和处理游戏逻辑的功能拆分为2组服务器:页面服务器和逻辑服务器。两者 之间可以通过remoting的方式进行数据通讯。将服务器分离后,随着页面服务器的增加,页面访问能力能应该能提升4~6倍。在往上逻辑服务器就会出现 访问瓶颈。解决方法可以让页面服务器在读取玩家数据时直接访问数据库或者增加一个对象缓存服务器。页面服务器只有在必要的时候(需要进行逻辑运算时)才访 问逻辑服务器,而逻辑服务器在玩家数据发生改变后更新对象缓存服务器和数据库。这样就可以大大降低逻辑服务器的访问次数,使页面访问能力进一步提升,轻松 突破万人在线。如果访问量还需要继续扩大,可以用httpd做前台负责相应图片以及css等静态文件。
     

    转载于:https://www.cnblogs.com/jack-feng/archive/2010/11/28/1890566.html

    展开全文
  • webgame《天途web》完整源码+架设工具+地图编辑器+GM管理+完整美术资源+文档打包下载 server端:php client端:AS3 数据库:mysql linux平台架设,在server文件夹内有官方自己写的简易架设工具,会自动生成数据库。 ...
  • 将会出现一种新型的加电功能:在某些平台上,会有标有“超级士兵图标”的方块(欢迎提及罗杰斯上尉 :slightly_smiling_face: )。 这种加电的效果是将加速度增加足够的倍数(比另一种类型的加电高),并且可以使陷阱...
  • Python 于 webgame 的应用(下)
                   

    赖勇浩(http://laiyonghao.com)

    (续上)

    游戏(服务器)是一种 CPU 密集、I/O 密集的应用,但是因为 GIL 的原因,Python 不能充分利用多核,所以一般都采用分布式的方案,那么 CPU 方面就没有太多好讲的了,不过 I/O 方面蛮有意思,可以讲一下。这里有没有 node.js 社区的朋友?(有人举手)。这句话你熟悉吗?(幻灯片上是一句话:I/O needs to be done differently.)这句话是 node.js 的作者说的,他说 I/O 该用不同的方法来实现啦。我觉得他说得很对,……后来他也做了 node.js。这里有一个 node.js 操作 DB 的例子,DB 操作必须是有 I/O,有 I/O 就有阻塞,有阻塞就并发性较差。node.js 是这样解决的:


    在操作数据库的时候,指定一个回调函数,在操作结束的时候,再由 node.js 把结果推送给你。借助 javascript 强大的闭包语法,可以写出“很漂亮”的带有回调的程序,而且看起来好像阻塞程序一样简单,又带有很高的并发性能。这就是 node.js 认为的 I/O 该有的样子。但是我不认同这句话。我认为 I/O 应该这样做,以下举个页游编程中常见的例子:


    上面是玩家输入用户名、密码后按下登陆键,从账号验证到进入游戏的流程。当用户名、密码发送到专门用以登陆的 signin 服务器,signin 需要先查询数据库验证用户名、密码。在此我们只考虑用户名、密码无误的情况,signin 知道用户名、密码无误之后,就得先告知 game 服务器,game 服务器会返回一个令牌给 signin,后面客户端可以凭此令牌登陆 game 服务器开始游戏之旅。这么复杂的流程,涉及到多条进程之间的通信,也就是有许多的 I/O。这种应用使用 node.js 来写的话,可能需要写上两三个回调,个人觉得是比较麻烦的。那么我觉得 I/O 最好能够像上图的代码中那样,……但这不就是传统的阻塞式的 I/O 吗?对的!我觉得 I/O 的接口应该跟之前无二,但是底层的实现需要改变;而不是像 node.js 一样,都带一毛 callback 的尾巴。那么怎么做到这一点呢?

    解决方案就是协程,协程才是未来。接下来介绍一下 gevent,gevent 能够让上图的代码运行起来。gevent 就是 libevent 加上 greenlet,简单介绍一下这两个库。libevent 提供指定的文件描述符事件发生时调用回调函数的机制,当然 timeout、signals 等也会调用回调。所以底层其实跟 node.js 是一样的,是有一个回调函数的,但是可以通过 greenlet 来封装出同步的 API,将丑陋的回调隐藏起来。greenlet 是一种 green thread……即一种用户空间线程,提供伪并发机制,所谓伪并发就是它并不能让你拥有充分利用多核 CPU 的性能,但他的好处是它的调度是虚拟机层面的,确切地说就是可以由程序员自己来进行调度。greenlet 是 Python 界对 green thread 的一种比较好的实现。

    如果使用 gevent 写一个简单的 echo 服务器,大概是这样子的:


    可以看到有一个 echo 函数,它处理每一个客户端连接,它读一行、写一行的方式来实现 echo 业务。大家可以看到代码还是有点长。类似 gevent 的项目还有沈崴的 eurasia,http://code.google.com/p/eurasia 。

    谈完了 I/O,接下来有必要看一下协议方面,因为页游对网络协议的处理还是颇有些要求的。这方面我比较推荐 google protobuf,这是一门协议描述语言,官方支持生成 C++/java/Python 的代码,有许多第三方插件可以生成其它语言的代码。通过 protobuf 可以很方便地描述业务协议,比如登陆的时候需要有 username 和 password,以及可选的 timestamp 之类的,protobuf 能够帮助你去做序列化和反序列化的工作。protobuf 还支持声明 RPC,也就是 service,这个特性能让大家方便地实现 RPC。我们也做了一套,就是 abu.rpc,它是基于 gevent 加 protobuf 来实现的。得益于 gevent,它提供了同步的 API,即当调用 RPC 的时候,就像调用普通函数一样,等待返回就可以了,无需回调。得益于 protobuf,它是一个二进制协议,所以每个数据包都有较小的尺寸。libevent 是一个高效的异步 I/O 库,所以 abu.rpc 也很快。不过 abu.rpc 最重要的两个特点是并行管线和双向调用。所谓双向调用就是指客户端可以调用服务器端,而服务器端也可以调用客户端提供的服务;也就是说客户端也是可以有服务的,它可以在创建的连接上绑定自己的服务。所谓的并行管线是这样的:


    有时候客户端会发起一个比较重量级的、比较耗时的请求,而后又发起一个较轻量的请求。如果没有并行管线的支持,那么虽然轻量级的请求很快就处理完了,但客户端也只能等到重量级的请求完成以后才能收到轻量级的请求的处理结果,如上图左。这样轻量级的请求就为别的请求所累,响应时间就变长了。如果有并行管线的机制,当轻量级的请求发过来时,经过简单的计算,马上就能够返回结果,就有更快的响应,更好的实时性。大家再来看一下使用 abu.rpc 的 echo 服务器:


    可以看到代码比直接使用 gevent 还是变短了不少的,复杂的地方可能是需要声明 service 吧。

    今天上午周琦(ZoomQuiet)提到使用 rabbitMQ 来解耦,的确,MQ 挺适合在应用(进程)间的,他提到的面向消息编程其实大概可以说就是发布订阅模式:我对什么东西感兴趣,到时候你就推送给我。现在大家都比较关注进程之间的 MQ,但其实在进程之内、模块之间,也是极其需要“MQ”的,所以我们实现了一个叫 message 的模块。可以订阅感兴趣的主题,当有这样的主题发布时,订阅的回调就会被调用到了。


    上图中右侧就是输出。通过 context 可以对消息处理流程做简单的干涉,比如某个订阅者处理完了认为别的函数都没有必要再调用之类,那么可以使用 context 来终止它。主要是受到 falcon 语言的启发而编写的,falcon 有丰富的语言特性,比如面向消息编程这个词,我第一次见就是在 falcon 编程语言的手册里看到的。关于这个库,我之前有写过一个 slide,放在这里:http://www.slideshare.net/laiyonghao/pythonmessage010 。在我们的《天下盛境》项目中,我们将其应用于任务、邮件以及好友等子系统中。举个任务子系统的例子,比如完成任务需要杀死 5 只怪物,针对这么多玩家做轮询的话是比较麻烦的,但通过订阅“怪物死亡”的主题,就可以在合适的时机去判定任务是否已经完成了,从而达到模块与模块间比较好的解耦的效果。

    最后,给大家介绍一个简单但又很难归类的库。在游戏中,需要大量处理二进制的数据,这些数据通常由不同的平台、操作系统生成或存储,比如在 32 位机上进行开发,但运营部署是在 64 位机器上,在 py2.6 的环境开发,在 py2.7 的环境部署,等。这时候往往产生一些兼容性的问题,这类问题很难查出真正的原因。比如内置函数 hash() 在 32 位机器上返回的是 32 位的有符号整数,在 64 位机器上返回 64 位的有符号数,如果两台机器需要比对哈希结果,稍加不注意就可能会出问题,解决问题分分钟需要两个晚上都很常见,因为代码没有任务地方出错,但逻辑全乱了套。因为我们在做客户端与服务器端的通信加密时也是使用 Python 去实现,所以遇到了不少类似的问题。后来我们总结出需要一系列绝对地返回 32 位带符号整数的函数,所以我们编写了这个 absolute32 程序库。它很简单,只是对标准库的几个函数进行了封装,提供了 hash/add/crc/adler 等函数。以 add 为例,它对溢出的的处理是与 C 语言一样的,而不是像 Python 那样自动转换为 long 类型。这个库的几个函数我们在 py2.6/py3.1 和 32bit/64bit ubuntu 是进行了交叉测试,可以很好的简单我们的兼容性问题。

    以上就是我今天要介绍的内容,谢谢大家。



               
    展开全文
  • SF webgame等快速建站利器! APMServ 5.2.6 是一款拥有图形界面的快速搭建Apache 2.2.9、PHP 5.2.6、MySQL 5.1.28&4.0.26、Nginx 0.7.19、Memcached 1.2.4、phpMyAdmin 2.11.9.2、OpenSSL、SQLite、ZendOptimizer,...
  • cfc4n · 2014/07/29 13:38from:http://www.cnxct.com/experience-with-webgame-of-security-and-defense/0x01 背景十一的假期间,在知乎上看到一个问题《网页游戏都有哪些安全问题?》,我是一个网页游戏开发者,对...

    cfc4n · 2014/07/29 13:38

    from:http://www.cnxct.com/experience-with-webgame-of-security-and-defense/

    0x01 背景


    十一的假期间,在知乎上看到一个问题《网页游戏都有哪些安全问题?》,我是一个网页游戏开发者,对这个问题非常感兴趣,印象比较深刻。当时是在游玩,也没时间细看这个问题。后来,在微博上,有一位朋友的转发,又让我看到这个问题,冥冥中,有种想回答的冲动。上周六时,研发部门内部周会时,听到其他项目组的一个整型溢出问题,导致刷钱的bug,又让我想起这个问题,更加坚定我要回答这个问题的决心,总结一下这项目中,所有经历过的webgame安全问题的经验,以加固当前项目安全壁垒,避免损失。亦可分享给其他做webgame研发的朋友,做交流探讨。

    知乎中的原问题是『网页游戏都有哪些安全问题?』,我觉得不妥,我给改成了『网页游戏都有哪些安全问题?如何做得更安全?』,同时,问题也从『大家来研究探讨一下,网页游戏攻防技术。必定,这个话题很敏感。目前,网页游戏已经很多了,会不会被黑产盯上?网页游戏会不会被黑,数据库会不会被拖库』改成了『大家来研究探讨一下,网页游戏攻防技术。必定,这个话题很敏感。目前,网页游戏已经很多了,会不会被黑产盯上?网页游戏会不会被入侵?入侵方式有哪些?如何做好网页游戏的入侵防御?挽救措施有哪些?如何才能最小化减少厂商损失?入侵方式有哪些?如何做好网页游戏的入侵防御?挽救措施有哪些?如何才能最小化减少厂商损失?』,更改的理由是『本文原提问者开篇提到「大家来研究探讨一下,网页游戏攻防技术。」,那么应该不光提到如何入侵,更应该提到如何防御,应该细心描述漏洞形成原理,规避方式,以提高研发者技能水平;应该详细讲解安全事件发生后,如何最小化减少厂商损失,减少用户损失,保护游戏平衡。』,幸运的是,这个修改,被知乎通过了。对此,表示感谢。

    在后来阅读这篇提问以及回答时,已经有几位网友回答了,多数是站在安全工作者角度上回答了这个问题。在这篇日志里,我将以webgame研发者角度,切合游戏业务模块逻辑,从业务需求,数据库设计,程序编写,操作方式上来讲解漏洞形成原理,规避方案,也欢迎大家讨论。

    0x02 登录认证


    近几年,网页游戏几乎都是以联运方式运营,意味着游戏服务器本身不保存用户密码,用户登录在平台,通过平台跟游戏服务器的接口对接登录。接口做加密认证。故webgame的帐号密码安全问题,这里不提了。但登录认证的hash字符串安全,也还是要注意的。比如登录hash字符串的生效时间,hash字符串的加密参数来源,比如包括用户名、登录IP,浏览器user-agent等数据,以防止改hash被泄漏了,也是很难通过服务器的验证。

    0x03 游戏充值


    webgame的游戏充值流程,跟普通网页充值流程一致,没有特殊的地方,其不同点就是跟其他众多平台做联合运营时,势必要每个公司做接口对接,且接口规范各式各样,且游戏厂商没有话语权,必须按照他们的接口规范来,这实在棘手。腾讯的充值接口的验证方式,安全性做的较为突出,大约代码:

    // 返回参数列表
    $signKey = array('openid','appid','ts','payitem','token','billno','version','zoneid','providetype','amt','payamt_coins','pubacct_payamt_coins');
    $sign = array();
    //从GET参数中,对比找出上面参数的值
    foreach($signKey as $key ) {
        if (isset($data[$key]))
        {
        $sign[$key] = $data[$key];  //只有 GET里有的参数,才参与sig的计算
        }
    }
    ######开始生成签名############
    //1: URL编码 URI
    $url = rawurlencode($url);
    //2:按照key进行字典升序排列
    ksort($sign);
    //3: &拼接,并URL编码
    $arrQuery = array();
    foreach ($sign as $key => $val ) 
    { 
        $arrQuery[] = $key . '=' . str_replace('-','%2D',$val);
    }   
    $query_string = join('&', $arrQuery);
    //4 以POST方式拼接 1、3 以及URL
    $src = 'GET&'.$url.'&'.rawurlencode($query_string);
    // ## 构造密钥
    $key = $this->config->get('qq_appkey').'&';
    //### 生成签名
    $sig = base64_encode(hash_hmac("sha1", $src, strtr($key, '-_', '+/'), true));
    if ( $sig != $data['sig'] ) {
        $return['ret'] = 4;
        $return['msg'] = '请求参数错误:(sig)';
        $this->output->set(json_encode($return));
        return ;
    }
    复制代码

    在此基础上,还可以做的严谨点:

    1, 增加随机参数名、参数值。随机参数名、参数值由联运方随机生成,按照参数名的字符串所属ASCII码顺序排序,参数名、参数值均参与sign的计算,增加暴力破解密钥(app key)难度。

    2, 增加回调验证订单号,金额信息。游戏充值服务器接收到充值请求时,反向到该平台回调接口,确认此笔订单有效性,以防止加密密钥泄漏的问题。

    0x04 远程文件引入


    在网页游戏的研发中,多数都是使用框架来做,即使用REQUEST来的参数,作为请求文件名的一部分,来使用,那么很容易形成远程文件引入的漏洞。在我们之前的游戏中,曾出现过一例这样的漏洞问题。

    // Load the local application controller
    // Note: The Router class automatically validates the controller path.  If this include fails it
    // means that the default controller in the Routes.php file is not resolving to something valid.
    if ( ! file_exists(APPROOT.'controllers/'.load('Router')->getDirectory().load('Router')->getClass().EXT))
    {
        load('Errors')->show404('Unable to load your default controller.  Please make sure the controller specified in your Routes.php file is valid.');
    }
    include(APPROOT.'controllers/'.load('Router')->getDirectory().load('Router')->getClass().EXT);
    load('Benchmark')->mark('load_basic_class_time_end');
    复制代码

    从代码以及案例图中,可以看到对于REQUEST的参数没有过滤处理,直接作为文件名来include引入的,故导致这种问题,类似上页图中,若PHP version < 5.3.4 ,还会发生Null(%00) 截断的问题,带来更大的安全问题。在我们新的项目中,我们更改了实现方式,我们游戏所有接口都会走gateway,gateway里,对控制器名做类名规范的检测处理,再在指定几个目录下做autoload加载文件,且还会对REQUEST的类名、方法用ReflectionClass反射类的处理,检测到类、方法、参数是否合法。一来避免『远程文件引入』漏洞问题,二来便于前后端联调时,抛出更详细的异常,方便调试。下面为参考代码:

    require_once CONFIG_PATH . "/auto.php";
    spl_autoload_register("__autoload");
    
    ……
    
    //默认消息格式
    $view->clear();
    $view->error(MLanguages::COM__INVALID_REQUST);
    $msg = new Afx_Amf_plugins_AcknowledgeMessage($val->data[0]->$messageIdField);
    $msg->setBody($view->get());
    $message->data = $msg;
    …
    
    $a = new Yaf_Request_Simple();
    $a->setControllerName($method[0]);
    $a->setActionName($method[1]);
    $objC = new ReflectionClass($method[0]."Controller");
    $arrParamenter = $objC->getMethod($method[1]."Action")->getParameters();
    $arrRequest = isset($val->data[0]->body[0]) ? (array)$val->data[0]->body[0] : array();
    $bCanCall = true;
    foreach ($arrParamenter as $objParam)
    {
        $parm = $objParam->getName();
        $bIsOption = $objParam->isOptional();    //是否为可选参数
        if (isset($arrRequest[$parm]))
        {
            $a->setParam($parm , $arrRequest[$parm]);
        }
        elseif ($objParam->isOptional())
        {
            //可选参数
        }
        else
        {
            $bCanCall = false;
        }
    }
    if ($bCanCall)
    {
        $rp = $app->getDispatcher()->dispatch($a);
        $msg = new Afx_Amf_plugins_AcknowledgeMessage($val->data[0]->$messageIdField);
        $msg->setBody($view->get());
        $message->data = $msg;
    }
    复制代码

    0x05 SQL 注入


    SQL注入原理、方式,跟普通web应用一样,没什么特别的,在使用REQUEST来的参数时,过滤处理即可。可能在消息格式,以及注入操作简便上,会蒙蔽研发人员的眼睛,被忽略掉了。比如我们项目的AMF消息格式,在前端界面没出来之前,我们后端程序员一般使用Pinta来模拟操作,调试程序。前端界面出来之后,会使用Charles proxy来捕捉http请求。在这些过程中,请求接口、参数的构造,没有普通web那么简单。研发人员也容易忽略对请求参数的过滤,故很容易形成这种问题。形成原理见:《WEB开发安全与运维安全浅见》,防御方式做过滤处理,或SQL预编译。

    为了提高游戏服务器的吞吐能力,网页游戏的架构也是一直在演变的。在之前以Mysql作为数据存储的webgame架构中,其他节点都是可以水平扩展,或者说依赖简单粗暴的增加服务器来解决,单单作为唯一数据存储中心,不能这么做。为此,很多webgame的数据存储改用Nosql来代替,甚至java、C/C++的游戏数据,直接在内存中操作,游戏关服时,才写入到DB中。故SQL注入的问题,也会越来越少。

    0X06 通讯协议与消息格式


    网页游戏虽然名字叫网页游戏,但通讯协议并非全是http,也有很多使用socket,以及http+socket并用的做法。我们是http协议+amf消息格式,以及socket并用来实现。在http与https的取舍上,我们考虑到ssl的启用后,大量的ssl解密加密运算,势必会增加服务器大量的CPU计算压力。而传输的内容,多数是游戏业务的操作,响应,是能接受被监听嗅探的行为的(认证信息除外)。站在安全角度,这不能理解。但站在产品角度,考虑一下 投入产出,然后选择http通讯,也是可以理解的。socket在我们游戏中,除了在聊天应用上使用外,在一些组队、帮派战之类需要多个玩家之间同步数据信息时,我们也会使用socket来推送数据。在使用socket作为所有业务传输的协议时,协议格式一般都是开源协议,比如msgpack、protobuf之类,或者自定义的协议。使用自定义协议时,务必检测整个消息包的每一个参数,类型范围,避免个别超大数值、边界数值出现,导致主程序内存越界,以至于服务宕机,无法正常服务的情况发生。

    0x07 金币复制-整型溢出


    上周周六开周会时,听到其他项目组的一个关于整型溢出导致产生刷金币的问题。在这里,我抽象该案例,分享一下。商城出售开启背包格子的所需道具『梧桐木』。在游戏中,用户包裹格子数量一般都会作为一个收费点,一款游戏的格子大约为每行7格子,一共8行这样。比如前面3行是默认开放的,第4行是收费的,而且第一个格子所需品梧桐木的价格1个银子,第二个梧桐木是2个银子,第三个是4个银子。依次类推,意味着这些梧桐木的价格总和其实就是一个第一项为1,公比为2,项为35的等比数列。 当用户选择购买梧桐木数量大于31时,比如32-36中这些数字时,这些等比数列的和就是大于2147483647。(只是举例,实际上不会以这样的价格出售物品)

    在java中,4字节的存放int型变量的范围是-2147483648至2147483647。在java、c的有符号int型中存储时,数的最高位描述符号位,4字节共32位,除去最高位的符号位,剩下31位,每个位上能表示2个数字,4字节的有符号的整数表示范围为:负整数2^31个,范围为『-1至-2147483648』;正整数2^31个,范围为『2147483647至1』。 比如下图(注意十进制数字跟二进制表示的变化顺序):

    当开启格子数字为大于31时,比如32,那么所需费用就是2147483647个银两,再买点其他物品,凑成超过2147483647的数字,比如又买了3个银子的其他道具,总共花费2147483650个银子,在4字节的有符号int中表示出来的结果,变成符号位为1,即负整数。数值位为0000000 00000000 00000000 00000010,也就是10000000 00000000 00000000 00000010,对应十进制的-2147483646。程序逻辑上,再判断现有银两是否足够支付此笔花费时,是通过的。当使用当前余额减去这笔花费时,将变成减去一个负数,那么实际上就是加上一个正整数。变成了自己银两账户余额的增长。而余额字段类型是long,则正确的存储了这些余额,溢出漏洞被利用。在C中,使用无符号的数值类型,即可完成数值类型溢出刷钱的行为,但在java中,好像没有无符号的类型。这也可以先确定所有参与计算的数值必须为正整数作为必要条件(游戏业务特性,游戏内所有数字,肯定全为正整数,甚至都不包括零),先做大小判断,再做正正相加,不能得负;负负相加,不能得正。来判断是否发生了溢出问题。在PHP中,不用担心溢出问题。 更多信息参考:《溢出,符号与进位

    不光是程序中,整型变量类型得需要注意,使用unsigned int在存储数据的DB中也要做同样的处理,对于存储整型数字的字段,均设置为unsigned int/tinyint/...。在游戏中,数字几乎全是自然数,几乎不会出现负整数的情况。

    0x08 道具复制-逻辑错误


    在我的新款webgame中,又发生了一起刷道具的问题,问题发生在背包内道具移动的业务上,业务需求如下:

    当从A位置移动到B位置时,若两者是同一类型,且可叠加(两者都是绑定或不绑定),则叠加数量到其中一个上,并销毁另外一个。 若不是同一类型,或不可叠加,则两者呼唤位置。 若目标位置为空,则把物品从A移动到B。 如果这个功能由你看写,你如何写? 程序员的全部代码在 gist:b7d794d3cb663dd86aad 可能比较长,其实这次出问题的在下面的代码中

    /**
         * 
         * 背包内道具移动
         * @param string $former  源位置格子号
         * @param int $target    目标位置格子号
         */
        public function MoveItemAction($former, $target)
        {
            $former = trim($former);
            $target = intval($target);
            if(!$former || $target < 1)
            {
                return $this->_view->error(MLanguages::COM__PARAMETERS_NOT_LEGAL);                  //参数异常;
            }
    
            //获取道具信息
            $former_item = $this->__mItems->getNumberItem($former);
            if(!$former_item)
            {
                return $this->_view->error(MLanguages::PACK__NOT_EXIST);                  //使用道具不存在;
            }
    
            $former_md5id = $former_item['md5_id'];
            $former_num = $former_item['number'];
            $former_base = $former_item['item_id'];
            $former_sup = $former_item['superpose'];
    
    
            //开启事务
            $this->__mRole->beginTrans();
            $target_item = $this->__mItems->getNumberItem($target);
            ......
    复制代码

    其出现问题部分就是如上这些,大家看代码时,会认为这前期的判断都是正确的,符合业务逻辑的,问题却发生了“来源格子”跟“目标格子”的判断,没有判断这两个参数是不是同一个位置,若是同一个位置,那么上面的所有业务逻辑判断都是合法的,下面的代码中,将根据这“两个”道具的属性进行堆叠,然后就发生了道具复制的问题.....

    修复方法想必大家都会,就是判断来源位置目标位置是否相同

    if(!$former || $target < 1 || ($former == $target)) //判断来源位置目标位置是否相同
    复制代码

    如果是你,你会犯这样的错误吗?我想.....呵呵...

    0x09 金币复制-并发请求


    Rpg类型的网页游戏中,多数都有道具出售的功能,直接卖到商店,以及道具材料从商店买入功能。当玩家同时针对买入、卖出两个操作,瞬间大量并发请求时,在服务器的处理逻辑一般有分别的两个进程处理,共享数据分别数据库中的对应账户余额表,如下图:

    //卖出
    // startTrans
    $iBalance = $obj->getBalance('user1');  //余额50
    
    //UPDATE `role_gold` SET gold = 150 WHERE role_id = 1
    if(!$obj->setBalance('user1',$iBalance + 100))
    {
        //rollback
    }
    //扣除物品
    if (!$obj->delItems($items))
    {
        //rollback
    }
    //commit
    
    //买入
    // startTrans
    $iBalance = $obj->getBalance('user1');    //余额50
    //UPDATE `role_gold` SET gold = 0 WHERE role_id = 1
    if(!$obj->setBalance('user1',$iBalance - 50))
    {
        //rollback
    }
    //发放物品
    if (!$obj->addItems($items))
    {
        //rollback
    }
    //commit
    复制代码

    卖出请求的处理进程为1,买入请求的处理进程为2。在进程1还没将结果写入到DB时,进程2也从DB读取到余额为50。这是,两个进程拿到的余额信息都是50。进程1按照逻辑代码,计算出剩余余额是150;进程2计算出的剩余余额是0。最后,不管那个进程最后写入余额,都是错误的结果。(注:这里的代码逻辑操作,跟mysql事务无任何关系,事务只能保证单个进程的事务范围内多条语句都正确执行,或回滚。比如能保证扣钱成功,且物品删除掉的两个语句都正确执行。能保证其中之一的语句执行失败时,都正确回滚。) 其实,在事物开启时候,SELECT语句是否可以取到最新的数据,或者是否需要等待锁释放,取决于MYSQL的事务隔离级别。在MYSQL的事务隔离级别中,有一下几种隔离级别:

    READ-UNCOMMITTED(读取未提交内容)级别

    READ-COMMITTED(读取提交内容

    REPEATABLE-READ(可重读)

    SERIERLIZED(可串行化)

    对于READ-UNCOMMITTED,可以读取其他事务中未提交的数据,而且据说性能还高不到哪里去,几乎没有在实际应用中使用;对于READ-COMMITTED,在同一事务中,会因为其他事务随时可能有新的commit,导致同一select可能返回不同结果。这个也不适合游戏业务;再说第四个SERIERLIZED,只要事务开启,所有其他查询,均排队等待该事务提交之后,对于上面提到的卖出买入情况,第二个事务的SELECT操作,不会立刻返回,会处于锁等待状态,一直到前一个事务结束。这个隔离级别,虽然能避免上面的问题,但性能较差,一般不会去使用。而REPEATABLE-READ隔离级别,也是mysql默认的隔离级别,从功能上,比较符合游戏业务需要,也应该是广大webgame架构中mysql的默认隔离级别。在使用REPEATABLE-READ隔离级别时,select的数据,都是事务未提交之前的数据,而每个事务都能正常成功执行,故错误的结果被执行出现。

    对于这个问题,你可能很快就给出解决办法,把UPDATE语句改为UPDATErole_goldSET gold = gold + 100 WHERE role_id = 1或者UPDATErole_goldSET gold = 150 WHERE role_id = 1 AND gold = 100来解决,但这种多个事务同时操作修改多个表的多条记录时,还容易引发死锁问题,比如《webgame中Mysql Deadlock ERROR 1213 (40001)错误的排查历程》。而且,当条件为跨表内数据是否存在,或者另外条件不在MYSQL中,而在其他网络接口的响应中时,如何做呢?

    0x10 金币复制--逻辑漏洞


    引用DNF的漏洞新闻 《利用网游漏洞狂刷游戏币赚钱 玩家自曝3天赚17万》

    玩家曝出刷币漏洞 一个游戏道具可刷400人民币 该漏洞到底是什么?原来游戏中“云幂袖珍罐”这个道具,可以开出2件一样的游戏装备,还有极少几率开出游戏币,开出的装备不值钱,但如果开出金币了,则分为5000万、8000万以及1亿游戏币。而1亿游戏币,按正常市场行情,可在交易网上卖400多元人民币。据玩家称,在游戏中,角色的装备是需要用包裹来存放的,不过目前角色的包裹最多只有48格,也就是只能存放最多48件装备。漏洞就是利用包裹的有限空间,存放47件装备(存放满了又无法开罐子),只留下一格空位,而在开“云幂袖珍罐”出装备时,就会因包裹空间不足,而导致开罐失败,而罐子还存在。玩家继续开罐,直到出现金币,但金币不会占据包裹的空间,因此开罐成功,然后罐子消失。发现这个漏洞后,部分玩家狂刷游戏币,然后马上在第三方交易平台出售游戏币,兑换成现金。

    这种问题,都是研发人员逻辑不严谨导致,这种问题,也较难发现。规避方式可以依赖下面提到的『运营数据监控』。

    0x11 道具复制--背包整理


    跟上面的卖出、买入一样,同时穿装备、整理包裹。在设计时,可能会将身上装备设计在装备表中;将不在身上的装备,设计到背包表中。当同时进行穿装备跟整理包裹的请求并发时,也会发生跟上面卖出,买入的情况,线程1读取DB,发现包裹里有这装备,然后准备删除背包表的这条记录,当准备写入到装备表时,另外一个整理包裹请求的线程来了,读取了整个背包表,进行道具的合并、排序。这时,之前的线程将这个装备写入到装备表,并删除了背包表里的数据,并提交事务。这个穿装备的所有操作都是合理、正常,且正确执行的。但另外一个整理背包的线程读取了之前的背包表里的数据,包括那件被穿上的装备。在游戏中,整理背包需要对可堆叠道具做堆叠操作的,意味着需要合并多个道具,删除部分道具。这意味着这里的操作,当前cgi线程的内存中的数据,将都会以覆盖的形式,写入到DB中,那么意味着,之前被穿到身上的那件装备,也会重新被写入到背包中。那就变成两张表里出现了两个相同唯一ID的相同属性的道具。玩家就可以把背包中的这个道具出售给其他玩家。

    在java或者C之类程序中,数据放内存中的游戏,也会存在这个问题,除非做读锁,但读锁会带来锁等待,锁等待会导致线程被占用,阻塞后面请求的处理,堆积大量请求。导致系统负载升高,服务器繁忙,以至于无法响应。好了,大约理解道具复制的形成原因了吗?这个问题,我们从根本原因想想,问题到底出现在哪里?如何规避呢?细心的同学不难发现,对于穿装备的操作结果,会对下一个请求产生影响的,当前操作未得到服务端响应之前,服务端是不能处理下一个响应的。对此,我们做了响应处理锁--『用户并发请求锁』。

    用户并发请求锁的实现,php中session以文件形式存储时,php会对session文件加锁,不释放(如果不特意执行session_write_close),知道当前响应完成。另外一个线程才可以正常读取,这简介的形成了单个用户的并发请求锁,但是,后面的进程一直处于等待状态,也会占用一个php-fpm进程,阻塞其他用户的正常请求对php线程的使用。为此,我们使用NOSQL的K-V形式结构,以user_name为key的形式,实现用户并发请求锁,比如 redis的setnx接口,原子性判断操作有则返回false,,没有就添加一个,返回true。那么,对于下一个请求,setnx时,返回false,有这个key了,那么立刻抛出异常,结束响应,FLASH根据异常内容,提醒用户不要进行恶意操作。即不会发生并发请求,又不会阻塞请求处理。同时,在请求结束的析构函数里,对这个锁进行删除操作,不影响下一个正常请求。若因为程序异常,发生语法错误,导致析构函数没法执行,没有删除用户锁时,可以在生成锁的时候,设置过期时间,比如5秒,甚至2秒,利用nosql的过期机制,实现用户解锁,避免用户长时间无法正常游戏。

    0x12 类CC攻击-多用户共享资源锁的timebomb


    我们现在研发的项目,是以NOSQL Redis作为DB,来存储数据的,redis并没有成熟的事务处理机制,watch甚至算不上关系型数据库中的事务处理。对此,更需要对表进行加锁解锁。java之类语言的项目,很多都是直接操作内存的,更是需要资源锁,来解决并发问题,解决多个请求操作同一份数据的问题。公司有另外一个项目,出现过一次因为锁的颗粒度较大,带来的锁等待timebomb的问题,也导致了线程繁阻塞忙,请求堆积,系统负载上升,导致宕机的问题。这个项目的锁是针对所有用户的锁,每个用户的请求发来时,当前线程会对所有用户的数据加锁,直到响应完成,才释放掉。这么做,是为了解决因当前操作,会影响到其他用户数据,比如多人PK,多个玩家之间的交互。

    当其他请求一并发来时,那么资源会立刻被锁住,直到上一个请求结束,才释放锁,那么其他线程都处于等待状态。用户基数小时,是看不出来锁带来的影响的,内存操作都比较快。当用户基数大时,或者说请求数增大时,后面的请求的等待时间会越来越长,超过webserver的等待时间,直接返回timeout,不能正常提供服务。

    这种问题的发生,是因为锁的颗粒太大了,不应该将所有用户都锁住,最好细化到当前请求所影响到的单个用户,只锁住单个用户的数据。这样,才减少timebomb的发生。

    0x13 其他


    知乎里的朋友提到,很多webgame 的前端做了判断,而后端没做判断的问题,这种问题,实属不该存在。在我们的项目中,后端做的验证判断,远比前端多的多。有时候,为了界面上的动画表现,前端flash一般会在用户操作之后,立刻渲染,然后,再根据后端响应,决定是否继续做界面元素改动。比如脱装备,玩家操作时,会先渲染装备从角色面板,跳到背包里的动画,然后,再根据后端响应结果,决定是否回滚动画。这样,避免显得操作后,一定时间的反映迟钝假象,以提高用户体验。当然,后端是一定会做判断的,判断角色背包是否有空格之类。现在的webgame研发,一般都不会存在前端判断,而后端不判断的做法了。如果有,也应该是个别遗漏情况。

    比如去年的time33算法的hash dos的问题,使用json消息格式的webgame一定要注意,php只是在接收请求时,做了最大数量的限制。但在json解码之后的数据中,是没有处理的。这里千万别忘记了。

    0x14 运营数据异常监控


    再完善的防御措施,都仍会有安全漏洞。适当的监控措施,也一定要有,监控等级、金币、游戏币、经验、珍贵物品的变化等等,一旦发现,立刻报警,在漏洞未扩散之前,第一时间去修复漏洞,以减少损失,维护游戏平衡。

    0x15 日志系统


    日志系统一定不能漏掉,所有操作,必须写入日志,当安全事件发生后,可以作为各种数据回滚,交易纠纷处理的可靠数据。也是作为数据监控的最准确的数据来源。

    一个真实的故事。去年6月份,我们项目新上线一个系统,以及腾讯充值接口V2升级V3,涉及充值代码改动,研发测试、策划测试、QA测试完毕之后,上线到个别服务区,观察情况。每次新版本上线,整个项目组都会持续观察数据情况,尤其是充值总额, 10、50、100的涨,突然,总额下降了。充值总额下降了,这可是总额啊,只能增加,是不会下降的。肯定哪里有BUG,DBA直接看binlog,查充值记录相关的SQL语句,最后发现充值系统的sql语句为UPDATE table set gold_num = $num,is_pay =1 ,没有WHERE,没有WHERE啊,多么弱智的BUG,这尼玛能容忍么?肯定要拉出来,弹JJ弹到死。当我从SVN日志中看到涉及这个文件的修改者时,我立刻石化了,悄悄的修了bug,默默的上传......

    事情是发生了,原因很弱智。是我自己,忘记写where条件,由于框架封装了,问题并不容易被发现。而且自己测试充值都是正确的,包括后来的策划测试、QA测试,都没有发现问题。所属功劳,就是“数据监控系统“,所以,我们游戏开发商,第一时间,比用户还早的发现了问题所在。数据监控,一定必不可少。

    至于修复方案,那要感谢日志系统。每笔充值,都有双份日志,一是各个游戏大区自己的DB中。二是充值中心中。充值中心负责跟其他各大平台对接。这次的事故,影响游戏大区的数据,并未影响到充值中心数据,故可以有据可查。这样,伟大的DBA可以更便捷、放心的修复数据了。对此,不管发生其他刷钱、刷装备、盗号之后的交易纠纷,都可以依赖日志来做处理。日志系统,也一定必不可少。

    从新功能发布,到发现BUG,到修复BUG,总共历时不到1小时(svn时间可以看出来,16:30对外的),可想而知,数据监控的效果多么值得称赞。新功能上线时,各个测试环节要去做。按大区服务器,做灰度发布也可以更小的减少bug影响范围,减少损失。

    如果你用了我画的小清新般的插图,请记得为图片写上署名来源,画图是最花费我时间的一件事。对了,看转载的同学,建议过来看原文,一来原文的排版格式会更适合阅读,二来原文会持续修正文中错误,增加内容。

    展开全文
  • Webgame是什么?

    2012-06-25 14:04:59
    一、Webgame介绍: Webgame(网页游戏)又称Web游戏,无端网游,简称页游。是基于Web浏览器的网络在线多人互动游戏,无需下载客户端,只需打开IE网页,10秒钟即可进入游戏,不存在机器配置不够的问题,最重要的是关闭...
  • Python 于 webgame 的应用(上)
  • server: WebGame服务端架构分析

    千次阅读 2014-12-09 14:04:09
    MMORPG服务器架构 一.摘要 1.网络游戏MMORPG整体服务器框架,包括早期,中期,当前的一些主流架构 ...2.网络游戏网络层,包括网络协议,IO模型,网络框架,消息编码等。...3.网络游戏的场景管理,AI,脚本的应用等。...
  • 魔兽世界网页游戏webgame源码(asp)web魔兽源码支持纯access模式,也支持sqlserver。仅供学习研究使用!我们这里只讨论纯access模式的架设。所以游戏运行的电脑上需要安装access数据库。首先,点击AspMao.exe ,就...
  • webgame开发简明教程

    千次阅读 2009-12-04 12:40:00
    webgame开发简明教程(1)研究所有点缺乏资料啊。讨论的问题怪怪的。只有很少是能用到的。一、简单的程序框架。webgame程序构成:三大部分。第一是数据流程。第二是程序。第三是美术。其中,数据流程包括了功能。也...
  • Yahle的blog: <br />http://www.cnblogs.com/yahle/category/122544.html <br /><br />在yahle的blog看到其对webgame架构的一个构想,假设这个构想要用java来实现的话,有几个方面想请教下大家 ...
  • 阿里巴 Arriba是使用Phaser3制作的完美的无限滚动平台。 安装 npm install 用法 npm start 执照 项目状态 这是目前正在开发的游戏。 这是我对游戏开发的第一次体验,我以此为契机学习了Phaser3框架。
  • Anxious是一个使用phaserJS模板开发的平台游戏,是一种协作游戏,或者它意味着您可以为游戏开发做出贡献,无论您是否是程序员。 游戏在Animus市进行,您将成为SIG或DORO,并且必须与内部恶魔作战。 该游戏旨在描绘...
  •  随着浏览器(PC/Mobile)...就我个人个遇到的几个框架及近期别人推荐的进行一些分析。主要针对使用HTML+CSS+JavaScript技术来开发游戏的技术做一分类,其它第三方语言实现的中间件平台只在最后简要介绍。  HT...
  • Webgame 设计与开发 第一章 简介

    千次阅读 2009-12-05 09:34:00
    Webgame 设计与开发 第一章 简介 内容简介 致谢 前言 第一章 简介 1.1 关于本书 本书是一本关于webgamed设计与开发的教程,内容包括五部分,第一部分介绍webgame的发展趋势,第二部分介绍webgame服务端设计,第三...
  • webgame游戏模式分析二

    2014-07-01 09:07:23
    www.webgame.com.cn  的web航海。对Ogame模式的修改值得借鉴。虽然是航海游戏,但核心模式没变。比较巧妙的把Ogame模式转化为了探险类的游戏。 这类修改,将6个系统重新进行了一定的包装。对新玩家有较强的吸引力...
  • flash webgame架构

    千次阅读 2011-10-22 13:34:21
    全策略的设定,是我们游戏和很多第三方平台合作的基石;它里面还定义着主程序被加载进来之前的游戏启动流程等等。"配置文件包":核心模块版本号啊,全局 文字说明啊,service接口定义啊,各个核心模块需要的配置...
  • 晚上看到我在silverlight webGame上的导师"深蓝色右手"拿到荣誉,觉得他名至实归。回想自己2010过年来到北京忙于一些琐屑的事情,好久没有动手写我的web传奇了。 去年在群里说我过年要开源我的Web传奇,写一些...
  • 它里面有安 全策略的设定,是我们游戏和很多第三方平台合作的基石;它里面还定义着主程序被加载进来之前的游戏启动流程等等。"配置文件包":核心模块版本号啊,全局 文字说明啊,service接口定义啊,各个核心模块...
  • 1 体系结构1.1 传统的网站的架构传统的网站...1.2 WebGame的架构WebGame可以看作是网站和游戏的结合体,因此它具备了这两类系统的特性。我们不但可以把WebGame看作是一个网站,也可以把它看作是一个网络游戏。的网站是
  • 2009:WebGame:何去何从

    2009-11-23 17:02:00
    回头看来2008年游戏行业最为值得一提的事情可能就是WebGame的兴盛和繁荣。在这一年,网络上各种类型的WebGame群雄并起,一年中市面上出现了逾百种“打开浏览市就能玩的游戏”。这种势头毫无疑问的会延续到新的一年,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 603
精华内容 241
关键字:

webgame平台