创建 MDT/CAD 系统的最佳方法是什么? (AJAX,SSE,WebSocket)

What is the most optimal way to create an MDT/CAD system? (AJAX,SSE,WebSocket)

向所有正在阅读的人问好,

我在一个网站的后端工作了很长时间,该网站提供逼真的移动数据终端和计算机辅助调度系统,用于在线角色扮演。

我最初利用 AJAX 调用 setInterval,它每 100 毫秒左右刷新页面的一部分,在 PHP 端,它运行一个 SQL 查询。

正如您想象的那样,这已被证明非常缓慢,甚至最终设法搞乱会话并让人们像其他人一样登录(不要问如何……我不知道)。我读过 WebSockets 和 SSE,但我需要真正决定一种方法并将整个系统转移过来,所以我的简单问题是...

优化我的系统的最佳方法是什么?我可以在实践中举一两个例子吗?

非常感谢您的阅读,

AJAX调用示例[​​=35=]

JQuery


      if (obs) {
        obs = false;
      }

      $.ajax({
        type:"GET",
        url: "mdt.php", 
        data: {  },
        success: function(result) {
          $("#mdt").html(result);
        }
      });
    };

setInterval(function() { if (!obs) { if (!paused) { refreshmdt(); } } }, 750);

mdt.php

session_start();
include("../config.php");
include("../backend.php");

$panicsql = getConnection()->query("SELECT * FROM Units WHERE Status='PANIC'");

if ($panicsql->num_rows > 0) {
    echo "<script>togglePanic('activate');</script>";
} else {
    echo "<script>togglePanic('deactivate');</script>";
}
?>
<!-- Terminal -->
<div class="col-md-6 col-sm-6 col-xs-12">
                <div class="x_panel">
                  <div class="x_title">
                    <h2><i class="fa fa-mobile"> Terminal</i></h2>
                    <ul class="nav navbar-right panel_toolbox" id="terminal">
                      <li>
                        <a href="bookoff.php"><button class="btn btn-block btn-danger"><i class="fa fa-sign-out"></i> Book Off</button></a>
                      </li>
                    </ul>
                    <div class="clearfix"></div>
                  </div>
                  <div class="x_content" id="" style="height:74.3vh;min-height:70vh;max-height:74.3vh;overflow:auto;text-align:center;">

                    <?php include("Ajax/status.php"); ?>
                    <br />
                    <h4><b>Change Status:</b></h4>
                    <br />
                    <p>
                      <a onclick="javascript:changeStatus('AVAILABLE');" class="btn btn-sq-sm btn-success">
                        <i class="fa fa-check fa-2x"></i><br/>
                        AVAILABLE
                      </a>
                      <a onclick="javascript:changeStatus('EN ROUTE');" class="btn btn-sq-sm btn-warning">
                        <i class="fa fa-taxi fa-2x"></i><br/>
                        EN ROUTE
                      </a>
                      <a onclick="javascript:changeStatus('ON SCENE');" class="btn btn-sq-sm btn-primary">
                        <i class="fa fa-map-marker fa-2x"></i><br/>
                        ON SCENE
                      </a>
                      <a onclick="javascript:changeStatus('PRISONER');" class="btn btn-sq-sm btn-info">
                        <i class="fa fa-user fa-2x"></i><br/>
                        PRISONER
                      </a>
                      <a onclick="javascript:changeStatus('UNAVAILABLE');" class="btn btn-sq-sm btn-default">
                        <i class="fa fa-times fa-2x"></i><br/>
                        UNAVAIL..
                      </a>
                      <a onclick="javascript:changeStatus('PANIC');startPanic();" class="btn btn-sq btn-block btn-danger">
                        <i class="fa fa-exclamation-triangle fa-1x"></i>
                        PANIC
                      </a>
                    </p>
                    <hr />
                    <p>
                      <a data-toggle="modal" data-target="#pnc" class="btn btn-sq btn-default">
                        <i class="fa fa-database fa-5x"></i><br/>
                        PNC
                      </a>
                      <a data-toggle="modal" data-target="#report" class="btn btn-sq btn-default">
                        <i class="fa fa-edit fa-5x"></i><br/>
                        REPORT
                      </a>
                    </p>

                  </div>
                </div>
              </div>

              <!-- Active Incident / Observations -->
              <div class="col-md-6 col-sm-6 col-xs-12">
                <div class="x_panel">
                  <div class="x_title">
                    <h2><i class="fa fa-comments-o"> Active Incident</i></h2>
                    <ul class="nav navbar-right panel_toolbox">
                      <li id="obsorinc">

                      </li>
                    </ul>
                    <div class="clearfix"></div>
                  </div>
                  <div class="x_content" id="activeInc" style="height:74.3vh;min-height:70vh;max-height:74.3vh;overflow:auto;">

                    <?php include("Ajax/activeInc.php"); ?>

                  </div>
                </div>
              </div>````

您现有的代码不需要太多更改即可转移到服务器发送的事件。

在前端,您拥有的 success 处理程序就是 message 事件处理程序。 (本着一步一步重构的精神,可以继续推现成的HTML。)

你在前端删除了间隔计时器,而是移到了后端。

(这样做的结果是套接字一直保持打开状态,并且 PHP 进程现在不断 运行,而不是每次轮询时启动和关闭。这可能影响扩展到大量客户端。)

后端需要更改的是将您当前拥有的内容包装在一个循环中,如下所示:

<?php
header("Content-Type: text/event-stream");
$prev_d = null;
while(true){
  $d = ...
  if($d != $prev_d){
    echo "data:".$d."\n\n";
    @ob_flush();@flush();
    $prev_d = $d;
    }
  usleep(100000); //Poll every 0.1 seconds
  }

作为第一步,您可以通过调用现有的 PHP 脚本来设置 $d

即使只是这些简单的更改,您的整体流程现在也变得更好了。是的,SQL 数据库仍然每 100 毫秒为每个活动用户轮询一次,但您现在仅在实际发生更改时才通过套接字发送数据。

下一步是将所有静态 HTML 放在客户端,而不是放在 PHP 脚本中。然后脚本只发回 SQL 查询的结果。这样效率更高,因此您的服务器和带宽负载会少一些。然而,主要优点是它将使系统更易于理解和维护。也更容易移植到其他语言或其他类型的客户端。

主循环会变成这样:

<?php
header("Content-Type: text/event-stream");
$prev_sql = null;
while(true){
  $panicsql = getConnection()->query("SELECT * FROM Units WHERE Status='PANIC'");
  if($panicsql != $prev_sql){
    $d = json_encode($panicsql);
    echo "data:".$d."\n\n";
    @ob_flush();@flush();
    $prev_sql = $panicsql;
    }
  usleep(100000); //Poll every 0.1 seconds
  }