我想实现一个简单的Server-Sent事件应用程序,其中客户端监听像这样的
的php文件<script src="eventsource.js"></script>
<script>
var es = new EventSource('../sse.php');
es.onmessage = function (event) {
var data = JSON.parse(event.data);
console.log('msg: ' + event.data);
};
es.onopen = function () {
console.log('connected');
}
</script>
然后我需要能够广播一条消息,并且每个连接的客户端都会同时获取它。
php文件将被另一个请求触发,它会将一些SSE数据“回显”给所有客户端。
这可能吗?我可以采取另一条路线吗?
提前谢谢
答案 0 :(得分:7)
PHP对此并不是很好。如果你有很多客户端在等待这个事件,你将需要为每个等待的客户端提供一个PHP解释器实例(可能还有一个apache线程)。
您可能会考虑做的是让事件驱动的服务器处理此问题。 Node.JS和Tornado(Python)是我过去在类似情况下使用过的两个环境。如果您使用Node.js,您可能需要查看socket.io - 它不使用Server Sent Events,但会使您想要的非常简单。
你可以并排两个网络服务器,你当前的服务器(我假设是Apache)和你写的一个处理等待更新的客户端。每当PHP服务器想要向等待的客户端发送消息时,PHP服务器通知另一个服务器(AMQP,ZeroMQ,redis Pub / Sub或非公共接口上的简单HTTP请求都是不错的选择),并且该服务器将消息传递给任何等待的客户。
你可以在github上看到一个非常简单的版本,我正在谈论使用node.js + socket.io(可以很容易地被SSE取代)。
答案 1 :(得分:1)
重要编辑:(一天后)
经过测试,我发现这是一个非常糟糕的解决方案。测试用例:
结果:
6个SSE连接已打开。但是有2个SSE连接待处理。服务器中的其他页面在关闭SSE客户端之前无法打开。
但是服务器可以通过ajax处理许多客户端(每1秒重复一次ajax)。
旧答案:
使用共享内存。
sse.php
<?php
header("Content-Type: text/event-stream\n\n");
header('Cache-Control: no-cache');
$key = "987654";
$permissions = 0666;
$size = 1024;
//Create or open the shared memory segment.
$segment = shm_attach($key, $size, $permissions);
$msg = ' null ';
$last_time = 0;
$time = 0;
while (1) {
if (shm_has_var($segment, 0)) {
$time = shm_get_var($segment, 0);
}
if (shm_has_var($segment, 0)) {
$msg = shm_get_var($segment, 1);
}
$now = time();
if ($last_time < $time) {
$last_time = $time;
echo 'data: msg(' . $msg . ') time(' . $time . ')';
echo "\n\n";
}
ob_flush();
flush();
sleep(1);
}
trigger.php
<?php
if (isset($_GET['msg'])) {
$key = "987654";// TODO: how to generate suitable key?
$permissions = 0666;
$size = 1024;
$segment = shm_attach($key, $size, $permissions);
$time = time();
$msg = $_GET['msg'];
shm_put_var($segment, 0, $time);
shm_put_var($segment, 1, $msg);
echo $time;
}
这种方式的缺点:
在我的实现中,sse.php只在一秒内发送最后一条消息。但你可以改进它并使用数据库。 (如果trigger.php在一秒钟内调用3次,则只保存最后一条消息)
答案 2 :(得分:0)
对于数量限制,由于浏览器限制到同一服务器的连接数,您可以通过重新配置来更改它。 firefox中有相同的默认号码(6)。
另外,我想知道如何在服务器端处理断开连接事件,如果有太多客户端使用SSE,则必须管理连接,即使其他资源(例如使用其他服务的套接字)也是如此。
答案 3 :(得分:-1)
所有页面不同时收到相同的消息。
他们只会在连接后收到消息。
如果需要,您可以查看WebSockets和/或Node.JS,它们可以提供更多“即时”消息传递。