I wanted to see how many simultaneous SSE (aka EventSource) connections I could setup, before overloading my machine. But testing with Firefox (Firefox 18 or Firefox 20) it stopped at 6 connections: the additional connections give no error, but do not send any data. (In Firebug I can see them there, waiting to connect.)
Chromium 25 also stopped at 6 connections, and so did Opera 12.15.
But it does not seem to be a server-side limit (I'm using Apache + PHP), as I could run all three browsers at the same time (i.e. 18 connections), and all are coming from the same IP address.
(Server and client are on the same machine, but using a 172.16.x.x address, not 127.0.0.1.)
So, I set the test up with CORS, and tried connecting to another server, which has a global IP. This time I get 12 connections for Firefox. Suggesting it is Apache configuration after all? No, Opera still only gets 6 connections. (No number for Chrome, as CORS does not appear to work.) I could also run connecting to both servers, for a total of 18 connections (but never any more) in Firefox, and a total of 12 in Opera.
As a 3rd test I moved both back-end and html to the remote server, and loaded the page that way. This time I hit a limit of 10 connections for Firefox!?! Opera still has a limit of 6. And Chromium (which works as there is no CORS involved this time) has a limit of 6.
I'd appreciate any insight into where this number 6 comes from, and if it is just coincidence that all three browsers are the same. And especially any insight into why Firefox is sometimes 6, sometimes 10, sometimes 12. (The SSE specification seems to leave the maximum number of connections undefined.)
Apache configuration is to use prefork, which means these settings:
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
(Both local (Ubuntu 10.04) and global (Ubuntu 11.10) servers have identical Apache settings here.)
I believe the key number there is that MaxClients is 150. I did a quick experiment changing StartServers to 50, instead of 5, but got identical results.
Here is the client-side HTML/javascript (1 or 2 lines to uncomment, and modify, if you want to experiment connecting to a different server; as given here it expects to find sse.php in the same directory as the HTML):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>SSE Stresstest</title>
</head>
<body>
<p id="err"></p>
<p id="x"></p>
<script>
function start(){
function onMessage(e){
document.getElementById('x').innerHTML+=e.origin+":"+this.dummy_n+":"+e.data+"<br/>";
};
function onError(e){
document.getElementById('err').innerHTML+="ERR:"+this.dummy_n+":"+JSON.stringify(e)+"<br/>";
};
for(var n=1;n<=32;++n){
//NB. 't' primarily to avoid caching
var url='sse.php?dummy_n='+n+'&t='+(new Date().getTime());
//if(n%2==0)
// url='http://example.com/sse.php?dummy_n='+n+'&t='+(new Date().getTime());
var es=new EventSource(url);
es.dummy_n=n; //So we can identify each one
es.addEventListener('error',onError,false);
es.addEventListener('message',onMessage,false);
}
}
setTimeout("start()",1000); //Only Safari needs the 1000ms delay.
</script>
</body>
</html>
And the backend sse.php script is like this:
<?php
$ip=array_key_exists('SERVER_ADDR',$_SERVER)?$_SERVER['SERVER_ADDR']:'cli';
header('Content-Type: text/event-stream');
header('Access-Control-Allow-Origin: *'); //CORS: allow access from anywhere
@ob_flush();@flush();
//Now the main loop
while(true){
echo "data:".gmdate("Y-m-d H:i:s,").$ip."
";
@ob_flush();@flush();
sleep(1);
}
?>
See Question&Answers more detail:
os