Reputation: 802
I want to implement a simple Server-Sent events app where clients listen to a php file like this
<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>
but then i need to be able to broadcast a message and every connected client gets it simultaneously.
The php file will be triggered by another request and it will "echo" some SSE data to all clients.
Is this possible? Is there another route i can take?
Thank you in advance
Upvotes: 6
Views: 6670
Reputation: 343
To the number limit, it is because of the browser limit number of connections to same server, you can change that by reconfiguration. There is same default number (6) in firefox.
Also, I have wonder how to handle the disconnect event on the server side, if too many clients use SSE, it is necessary to manage the connections, even when other resource such as sockets to other services used.
Upvotes: 0
Reputation: 2055
important EDIT: (after a day)
after testing i found this is so bad solution.
test case:
result:
6 SSE-connections opened. but 2 SSE-connections left pending. other pages in server cannot be open until close SSE-clients.
but server can handle many clients by ajax (repeat ajax every 1 second).
Old Answer:
use share memory.
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;
}
disadvantage of this way:
in my implementation sse.php send only last message in a second. but you can improve it and use database. (if trigger.php called 3 times in a second, then only last message saved)
Upvotes: 1
Reputation: 2737
PHP is not going to be great for this. If you have lots of clients waiting for this event, you're going to require an instance of the PHP interpreter (and probably an apache thread) for each client that's waiting.
What you might consider doing is having an event driven server handle this. Node.JS and Tornado (Python) are two environments I've used in the past in similar circumstances. If you use Node.js, you may want to look into socket.io for this -- it doesn't use Server Sent Events, but would make what you want very simple.
You could have two webservers side by side, your current server (I'm assuming Apache) and one written by you to handle the clients waiting for updates. Whenever the PHP server wants to send a message to waiting clients, the PHP server notifies the other server (AMQP, ZeroMQ, redis Pub/Sub or a simple HTTP request on a non-public interface would all be good choices), and that server passes on the message to any waiting clients.
You can see a very simple version of what I'm talking about using node.js + socket.io (Which could easily be replaced by SSE) on github.
Upvotes: 7
Reputation: 146310
All of the page will not get the same message simultaneously.
They will only get the message once they are connected.
If you want, you can look into WebSockets and/or Node.JS which could allow for more "instant" messaging.
Upvotes: -1