简单的在线网页游戏最终崩溃

时间:2017-01-03 17:17:24

标签: javascript php server

背景 我正在用PHP,JavaScript和HTML为网络制作一个简单的游戏。玩家控制屏幕上框的移动,并看到其他人用他们的盒子飞来飞去。

我有以下文件,我通过托管公司上传到我的域名:

  • index.html:带有一些按钮(例如,开始游戏)和框架(用于放入框)的文件。
  • server.php:从客户端接收消息,对数据库执行读/写操作,从数据库回显(使用echo)框到客户端的PHP脚本。不回应消息来自的播放器的框。
  • database.txt:包含玩家数据和下一个免费ID号的JSON文本文件。如果为空,它看起来像这样:{"players":[], "id": 1}玩家包含具有ID,位置和旋转等值的对象。
  • script.js:包含脚本的JavaScript文件,用于发送/接收消息,显示消息中的数据等。链接到index.html。移动你的盒子。

截图,两位参与者:

问题:游戏总是崩溃。迟早。这就是:

  1. 客户从server.php收到玩家数据,一切都很好。这可能是10秒或几分钟。
  2. 数据开始动摇,消息有时是 null 而不是实际数据。
  3. 接收的数据始终为 null 。数据库文件现在是{"players":null,"id":5}。 (“id”可以是任何数字,不一定是5)。
  4. 数据流的图片,从数据库打印播放器。两名球员。在此截图之前,许多行都包含有效数据。然后看到两个 null 消息。然后一段时间 null 永远。

    enter image description here

    我不完全确定问题出在哪里,但我猜它与server.php中的读/写有关。我觉得很多玩家的动作让程序更容易崩溃。此外,程序发送数据的频率也是如此。

    代码片段1:这是来自server.php的代码,它写入数据库。我有某种信号量flock( ... ))来防止客户端同时读/写(导致错误)。我有另一个函数, read ,这与此非常相似。这里可能出现的问题:

    • 信号量不正确。
    • fopen()的模式不正确。见PHP docs。模式 w 用于写入。标签 b 用于“如果在处理二进制文件时未指定'b'标志,则可能会遇到奇怪的数据问题......”
    • 因为我在写作函数中使用read()而发生了一些奇怪的事情?

    代码:

    // Write $val to $obj in database JSON
    function write($obj,$val){
       $content = read();
       $json = json_decode($content);
       $json->{$obj} = $val; // eg. $json->{'id'} = 5; 
       $myfile = fopen("database.txt", "wb") or die("Unable to open file!");
       if(flock($myfile, LOCK_EX|LOCK_NB)) {
         fwrite($myfile,json_encode($json));
         flock($myfile, LOCK_UN);
       }
       fclose($myfile);
    

    }

    Code Piece 2:这是我发送数据的代码。它通过setInterval()调用。在script.js

    // Send message to server.php, call callback with answer
    function communicate(messageFunc,callback){
      var message = messageFunc();
      if (window.XMLHttpRequest) {
        var xmlhttp=new XMLHttpRequest();
      }
      xmlhttp.onreadystatechange= function() {
        if (this.readyState==4 && this.status==200) {
          callback(this.responseText);
        }
      }
      xmlhttp.open("GET","server.php?msg="+message,true);
      xmlhttp.send();
    }
    

    这是我在server.php$receive = $_GET["msg"]中接收数据的代码。

    我目前解决的工作 这是我到目前为止所做的,但没有任何改变:

    • 将模式 b 添加到fopen()
    • flock()中读取/写入函数添加了server.php
    • script.js进行大量修改,我会说它外观/工作非常干净。
    • 检查memory_get_peak_usage(),并与托管公司核实内存限制。应该没问题。
    • 看看PHP垃圾收集和gc_enable()(我不知道为什么会改变任何东西)。
    • 大量测试,查看数据流。
    • 哭泣。

    结论:这种类型的应用程序是PHP的用途吗?你觉得怎么了?如果您想要更多我提供的代码/信息。非常感谢你。

1 个答案:

答案 0 :(得分:1)

以下是问题的根源:

$myfile = fopen("database.txt", "wb") or die("Unable to open file!");

注意behavior of the w open mode(强调我的):

  

仅供写作;将文件指针放在文件的开头,并将文件截断为零长度。如果该文件不存在,请尝试创建它。

在锁定文件之前会发生。发生的事情是,在此fopen()电话和以下flock()电话之间,该文件的内容长度为零,并且读者在此期间出现并读取空文件。

为什么在将空字符串解析为JSON时,这不会导致PHP出错?因为json_decode()有缺陷,并且当输入无效JSON而不是抛出异常时返回null。没关系,字符串"null"是有效的JSON - json_decode()使您无法区分表示空值和无效输入的有效输入的情况。如果json_decode()实际上引发了异常或触发了PHP错误(不要问我为什么PHP中需要两个错误信号机制),那么你就可以开始调试以找出文件为空的原因,你现在可能已经解决了这个问题!

... 叹息 ...

PHP的“设计”给我带来了麻烦。但我离题了。

要解决此问题,请在成功获取锁定后将打开模式更改为"cb"ftruncate($myfile, 0)

请注意c模式的行为,它实际上特别提到了您正在使用的方法(强调我的):

  

打开文件仅供写入。如果该文件不存在,则创建该文件。如果它存在,既不截断(而不是'w'),也不会调用此函数失败(如'x'的情况)。文件指针位于文件的开头。 如果在尝试修改文件之前需要获取咨询锁(请参阅flock()),这可能很有用,因为使用“w”可能会在获取锁定之前截断文件(如果需要截断,在请求锁定后可以使用ftruncate()