Javascript服务器端事件:多个客户端在侦听单个服务器实例

时间:2018-11-18 16:15:16

标签: javascript server-sent-events

我想用多个侦听单个服务器实例的客户端来实现服务器端事件。每当我的客户连接时,他们都会创建服务器的新实例。我希望他们都听同一个实例。

以下片段描述了服务器,Client1侦听“ Ping”,Client2侦听“ Pong”。运行时,每个客户端都会创建一个新实例,如浏览器中生成并显示的随机密钥所示。我的目标是他们用bot侦听同一个实例。我经过几个小时的调查,发现了很多信息并使用了其他的库,但我宁愿只使用本机,它在FreePBX环境中运行,其中包括bootstrap,jquery,socket.io等库。

sse-serv.php:

<?php
date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream");
$key = rand(1111, 9999); // a random counter
$counter=0;
while ($counter < 100) {
// 1 is always true, so repeat the while loop forever (aka event-loop)
  $curDate = date("Y-m-d H:i:s");
  $msg=array();
  $msg['count']=$counter;
  $msg['time']=$curDate;
  $msg['key']=$key;
  $json_msg=json_encode($msg);
  if ($ping) {
    echo "event: ping\ndata: $json_msg \n\n";
    $ping=false;
  } else {
    echo "event: pong\ndata: $json_msg \n\n";
    $ping=true;
  }
  $counter++;
  ob_end_flush();
  flush();
  if ( connection_aborted() ) break;
  sleep(1);
}
?>

服务器每隔一秒钟发送一次“ Ping”或“ Pong”事件。客户显示的正是我所期望的,RND $ Key的优势是不同的,因此它们显然是不同的实例。 (由于某种原因,它们都未显示在ps aux | grep sse-serv中。)

sse-client1.php:

<?php
session_start();
require_once('include.php');
require_once('/etc/freepbx.conf');
$dt=date("Y-m-d H:i:s");
?>
<html>
<head>
   <meta charset="UTF-8">
   <title>Server-sent events demo</title>
</head>
<body>
  <button>Close the connection</button>
<script>

  var button = document.querySelector('button');
  var evtSource = new EventSource('sse-serv.php');
  console.log(evtSource.withCredentials);
  console.log(evtSource.readyState);
  console.log(evtSource.url);
  var eventList = document.querySelector('ul');
  evtSource.onopen = function() {
    console.log("Connection to server opened.");
  };
  evtSource.onmessage = function(e) {
    var newElement = document.createElement("li");
    newElement.textContent = "message: " + e.data;
    eventList.appendChild(newElement);
  };
  evtSource.onerror = function() {
    console.log("EventSource failed.");
  };
  button.onclick = function() {
    console.log('Connection closed');
    evtSource.close();
  };
evtSource.addEventListener("ping", function(e) {
var newElement = document.createElement("li");
  var today = new Date();
  var h = today.getHours();
  var m = today.getMinutes();
  var s = today.getSeconds();
  var ntime= h + ":" + m + ":" + s;
   var obj = JSON.parse(e.data);
newElement.innerHTML = "Key: " + obj.key + ping at " + obj.time + " Local time: " + ntime + " counter: " + obj.count;
eventList.appendChild(newElement);
}, false);
</script>
</body>
</html>

Client2与client1完全一样,只是它侦听“ Pong”而不是“ Ping”。

当我同时运行两个客户端时,我会得到:

Client1:

Key: 2642 ping at 2018-11-18 06:27:19 Local time: 6:27:19 counter: 1
Key: 2642 ping at 2018-11-18 06:27:21 Local time: 6:27:21 counter: 3
Key: 2642 ping at 2018-11-18 06:27:23 Local time: 6:27:23 counter: 5
Key: 2642 ping at 2018-11-18 06:27:25 Local time: 6:27:25 counter: 7
Key: 2642 ping at 2018-11-18 06:27:27 Local time: 6:27:27 counter: 9

Client2

Key: 1818 pong at 2018-11-18 06:27:18 Local time: 6:27:18 counter: 0
Key: 1818 pong at 2018-11-18 06:27:20 Local time: 6:27:20 counter: 2
Key: 1818 pong at 2018-11-18 06:27:22 Local time: 6:27:22 counter: 4
Key: 1818 pong at 2018-11-18 06:27:24 Local time: 6:27:24 counter: 6
Key: 1818 pong at 2018-11-18 06:27:26 Local time: 6:27:26 counter: 8

此输出正是我想要的,除了不同的键可以证明每个客户端都在运行sse-serv.php的单独实例。我需要他们都收听sse-serv.php的现有实例,该实例将作为守护程序运行并广播给所有客户端。我该怎么办?

3 个答案:

答案 0 :(得分:0)

编辑:我在这个答案中跳过了很多细节。我在这里提到WebSocket是因为最终您可能会发现您需要的功能/灵活性支持要比服务器发送事件所提供的更多。

使用PHP中的WebSocket服务器将获得更好的成功。您只需创建一个长期运行的过程,即可将您的网络服务器作为标准PHP MIME类型调用该过程。这意味着(如您所知)对于对PHP端点的每个请求,您都启动了一个新的PHP实例。您的PHP页面网址很可能使用http:// ...

Web套接字服务器URL以ws://开头。这告诉服务器使用单个现有的正在运行的进程。然后,网络套接字服务器会跟踪所有可用的“频道”,并广播到这些频道。

对此最快的解决方法是让您使用在此处找到的棘轮WSS:http://socketo.me

那应该可以解决您的问题。如果您喜欢自己编写,则可以使用很多资源。

答案 1 :(得分:0)

每个PHP脚本默认都是完全隔离的。如果您只是想快速制作原型,我建议您使用其他环境。在node.js中,所有内容都是共享的,而重新做您的示例将是微不足道的。

如果需要PHP,并且您愿意花费额外的时间,请不要使PHP处理多个连接,而应将应用程序的“发布/订阅”方面卸载到专用服务器上。有很多具有良好PHP客户端的类似pub / sub的系统。每个具有不同的可伸缩性属性和复杂性。 Redis入门很容易。

答案 2 :(得分:0)

这正是我所需要的。所以现在我有用PHP和客户端库编写的自己的服务器,可以处理 通过ws:// wss:// tcp:// ssl://进行连接 我正在我们的Intranet内的Web应用程序中即时使用此版本。

看看https://github.com/napengam/phpWebSocketServer