实时传感器数据作为从Python到PHP的服务器发送事件(SSE)?

时间:2017-06-05 02:35:15

标签: php python sockets real-time server-sent-events

我正在更新呈现实时传感器数据的Web应用程序,其中当前的第一次迭代通过连续的AJAX轮询来完成此操作。 但是,为了使这更像是一个真正的实时'应用程序,我希望它是基于事件的。

我一直在阅读基于事件的技术,并且基于实时通信只需要一种方式(服务器 - >客户端)的事实,我选择使用Server-现在发送事件(SSE)而不是像websockets这样的东西。 正如here on the Mozilla Docs所述,这很容易在服务器端实现,例如(稍微简化):

<?php
// SSEscript.php
date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream\n\n");

while (1) {
   if ($new_data_available) {
      echo "data:". $data;
   } 

   sleep($short_time_to_spare_cpu);
}
?>

并在客户端使用:

<script>
var evtSource = new EventSource("SSEscript.php");

evtSource.onmessage = function(e) {
   var data = e.data;
   // Do something with data object
} 
</script>

以上所有对我来说都很好。 但是,传感器数据最初是由在服务器上连续运行的Python脚本检索的,因此在检索传感器数据时如何将传感器数据从Python脚本立即传输到PHP脚本,以便生成并发送事件?

我可以做下面描述的事情吗? : scenario1

同时所有新数据都存储在MySQL数据库中,因此我当然可以让PHP脚本经常查询数据库以获取新条目,但必须有更聪明的方法。那么我可以在图像中同时发生2.1和2.2吗?

我在这里找到的所有答案都描述了如何通过让PHP执行Python脚本来传输数据,但这不是我想要的,因为无论用户是否要求数据都必须运行。

是一种插座方式,如果是这样,你能指出我的方向吗? 我希望你能帮助我!

1 个答案:

答案 0 :(得分:1)

我使用redis在python和redis之间进行信令。在python完成所有工作之后,将令牌(或最新数据)转发到redis队列中。在PHP中,我使用while(true)循环来保存请求,并使用redis lpop(queue,timeout)等待令牌,然后发送数据,如下所示:

<?php
    require __DIR__.'/predis-1.0/autoload.php';
    header("Content-Type: text/event-stream");
    header("Cache-Control: no-cache");
    header("Connection: keep-alive");

    $lastId = isset($_SERVER["HTTP_LAST_EVENT_ID"]) ? 
              $_SERVER["HTTP_LAST_EVENT_ID"] : null;
    if (isset($lastId) && !empty($lastId) && is_numeric($lastId)) {
        $lastId = intval($lastId);
        $lastId++;
    }

    $index = isset($_GET['index']) ? $_GET['index'] : null;

    echo "retry: 2000\n";

    $client = new Predis\Client();
    while (true) {
        $data = $client->blpop('queue',5);
        if ($data) {
            error_log("$index : " . strlen($data));
            sendMessage($lastId, $data);
            $lastId++;
        }
    }

    function sendMessage($id, $data) {
        echo "id: $id\n";
        echo "data: $data\n\n";
        ob_flush();
        flush();
    }