服务器发送的事件和php - 什么触发服务器上的事件?

2022-08-30 07:21:07

HTML5 Rocks有一个关于服务器发送事件(SSE)的很好的初学者教程:

http://www.html5rocks.com/en/tutorials/eventsource/basics/

但是,我不明白一个重要的概念 - 是什么触发了服务器上导致发送消息的事件?

换句话说 - 在HTML5示例中 - 服务器只需发送一时间戳:

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
function sendMsg($id, $msg) {
  echo "id: $id" . PHP_EOL;
  echo "data: $msg" . PHP_EOL;
  echo PHP_EOL;
  ob_flush();
  flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));

如果我正在构建一个实际示例 - 例如,Facebook风格的“墙”或股票行情,其中服务器每次更改某些数据时都会向客户端“推送”新消息,这是如何工作的?

换句话说...PHP 脚本是否有一个连续运行的循环,检查数据中的更改,然后在每次找到时发送一条消息?如果是这样 - 您如何知道何时结束该过程?

或者 - PHP脚本是否只是发送消息,然后结束(就像HTML5Rocks示例中的情况一样)?如果是这样 - 如何获得持续更新?浏览器是否只是定期轮询 PHP 页面?如果是这样 - 这如何成为“服务器发送的事件”?这与在 JavaScript 中编写使用 AJAX 定期调用 PHP 页面的 setInterval 函数有何不同?

对不起 - 这可能是一个非常天真的问题。但是我能找到的例子中没有一个能清楚地说明这一点。

[更新]

我认为我的问题措辞不当,所以这里有一些澄清。

假设我有一个网页,应该显示苹果股票的最新价格。

当用户首次打开页面时,该页面将使用我的“流”的 URL 创建一个事件源。

var source = new EventSource('stream.php');

我的问题是 - “流.php”应该如何工作?

喜欢这个?(伪代码):

<?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
    function sendMsg($msg) {
        echo "data: $msg" . PHP_EOL;
        echo PHP_EOL;
        flush();
    }

    while (some condition) {
        // check whether Apple's stock price has changed
        // e.g., by querying a database, or calling a web service
        // if it HAS changed, sendMsg with new price to client
        // otherwise, do nothing (until next loop)
        sleep (n) // wait n seconds until checking again
    }
?>

换句话说 - 只要客户端“连接”到“流.php”,它是否会保持打开状态?

如果是这样 - 这是否意味着您运行的线程数与并发用户数一样多?如果是这样 - 这是否远程可行,或者构建应用程序的适当方法?你怎么知道什么时候可以结束一个实例?stream.phpstream.php

我天真的印象是,如果是这样的话,PHP就不适合这种服务器。但是到目前为止,我看到的所有演示都暗示PHP对此很好,这就是为什么我如此困惑的原因......


答案 1

"...只要客户端“连接”,“流.php”是否保持打开状态?

是的,你的伪代码是一种合理的方法。

“你怎么知道什么时候可以结束一个流.php实例?”

在最典型的情况下,当用户离开您的网站时,就会发生这种情况。(Apache识别闭合套接字,并杀死PHP实例。您可能从服务器端关闭套接字的主要时间是,如果您知道在一段时间内不会有数据;您向客户端发送的最后一条消息是告诉他们在特定时间回来。例如,在您的股票流案例中,您可以在晚上8点关闭连接,并告诉客户在8小时内回来(假设纳斯达克从凌晨4点到晚上8点开放报价)。星期五晚上你告诉他们星期一早上回来。(我有一本即将出版的关于SSE的书,并专门用了几节来讨论这个主题。

"...如果是这种情况,PHP不是适合这种服务器的技术。但是到目前为止,我看到的所有演示都暗示PHP对此很好,这就是为什么我如此困惑的原因......”

好吧,人们认为PHP不是一种适合普通网站的技术,他们是对的:如果你用C++替换整个LAMP堆栈,你可以用更少的内存和CPU周期做到这一点。但是,尽管如此,PHP仍然为大多数网站提供支持。对于Web工作来说,这是一种非常高效的语言,因为它结合了熟悉的类似C的语法和如此多的库,并且对于管理人员来说,这是一种令人欣慰的语言,因为有大量的PHP程序员可以雇用,大量的书籍和其他资源,以及一些大型用例(例如Facebook和Wikipedia)。这些基本上与选择PHP作为流媒体技术的原因相同。

典型的设置不会是每个PHP实例到纳斯达克的一个连接。相反,您将拥有另一个进程,该进程具有与纳斯达克的单个连接,或者可能是从集群中的每台计算机到纳斯达克的单个连接。然后将价格推入SQL / NoSQL服务器或共享内存。然后PHP只是轮询共享内存(或数据库),并将数据推出。或者,有一个数据收集服务器,每个 PHP 实例都会打开一个与该服务器的套接字连接。数据收集服务器在接收更新时将更新推送到其每个PHP客户端,然后又将数据推送到其客户端。

使用Apache + PHP进行流式传输的主要可扩展性问题是每个Apache进程的内存。当达到硬件的内存极限时,做出业务决策,将另一台机器添加到集群中,或者将Apache从循环中剔除,并编写一个专用的HTTP服务器。后者可以在PHP中完成,因此您可以重用所有现有的知识和代码,或者您可以用另一种语言重写整个应用程序。我心中的纯开发人员会用C++编写一个专用的、简化的HTTP服务器。我心中的经理会添加另一个框。


答案 2

服务器发送的事件用于从服务器端到客户端的实时更新。在第一个示例中,来自服务器的连接不会保留,客户端每 3 秒尝试重新连接一次,并使服务器发送的事件与 ajax 轮询没有区别。

因此,要使连接持久化,您需要将代码包装在循环中并不断检查更新。

PHP是基于线程的,更多连接的用户将使服务器耗尽资源。这可以通过控制脚本执行时间并在超过一定时间(即10分钟)时结束脚本来解决。API 将自动再次连接,因此延迟在可接受的范围内。EventSource

另外,请查看我的 PHP 库,了解服务器发送的事件,您可以了解有关如何在 PHP 中执行服务器发送事件的更多信息,并使其更易于编码。


推荐