Suppose there is a webpage with dynamically generated content -- say a div containing the current number of connected browsers. When the count changes on the server I want all connected browsers to reload the count so that everyone sees the increment/decrement.
What's the best way to accomplish this?
Keywords: ajax, broadcast, browser, div, jquery
I think COMET might be what you're looking for. Web Sockets would be ideal but lack of browser adoption wouldn't make it practical right now.
HTTP protocol is stateless by design. The only one way to achieve this is to implement client-side polling via AJAX.
Here's how to do server-push using ajax long-polling. The browser makes an ajax request which initiates server-side self-polling. The ajax request remains open, waiting for a response until the file changes, and as soon as it gets a response, it makes a new long-polling request.
Here's what it looks like with jQuery and php, implementing the example of live-updating a div in the html showing the number of clients currently connected:
index.html:
<html>
<head>
<title>Comet Test</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="longpolling.js"></script>
</head>
<body>
Number of connected users: <div id="total">0</div>
</body>
</html>
longpolling.js:
$(document).ready(function() { connectToServer(1); });
function connectToServer( incp ) {
$.get("LongPolling.php",
{ inc: incp },
function(resp) {
$('#total').html(resp);
connectToServer(0);
}
);
}
LongPolling.php:
<?php
# (over)write file with contents, locking the file while doing so.
# just barf and die if there's an error.
function update($file, $contents)
{
$f = fopen($file, 'w');
if(!$f) { echo "ERROR1"; exit; } # couldn't open file for writing.
if(!flock($f, LOCK_EX)) { echo "ERROR2"; exit; } # couldn't get lock.
fwrite($f, $contents);
fclose($f); # this also releases the lock.
return $contents;
}
# fetch the contents of the given file.
# if the file doesn't exist, create it with contents "0"
function fetch($file)
{
if(file_exists($file)) {
if(!is_readable($file)) { echo "ERROR3"; exit; }
$x = file_get_contents($file);
} else {
$x = 0;
update($file, $x);
}
return $x;
}
$fc = 'connx.txt'; # file that stores the number of connections.
if ( $_REQUEST['inc'] == 1 ) { # someone just connected.
echo update($fc, fetch($fc)+1);
} else { # someone is reconnecting (also happens immediately after connect).
$last = filemtime($fc);
do { # wait until some other instance causes $fc to change...
sleep(1);
clearstatcache(); # otherwise filemtime() results are cached!
} while(filemtime($fc) == $last);
echo fetch($fc);
}
?>
NOTE: This does not track disconnects, so it's more like live-tracking the total number of pageviews.
See Running server-side function as browser closes for info on keeping track of browser disconnects, ie, server-side action on client disconnect.
Reverse AJAX is what you need. It's briefly explained in the DWR web page: http://directwebremoting.org/dwr/reverse-ajax/index.html - you can probably use one of the three flavours with the library you are using for ajax calls.
As of Dec 2014, there is a W3C proposed recommendation called Server Sent Events (SSE) that would allow you to do that over HTTP: http://www.w3.org/TR/eventsource
It seems that it is a standardization of a group of techniques known as Comet. (which Darrel linked to in his answer)
A full example from 2013 with Sinatra can be found at: http://html5hacks.com/blog/2013/04/21/push-notifications-to-the-browser-with-server-sent-events/
There is also a 2010 HTML5 Rocks article: http://www.html5rocks.com/en/tutorials/eventsource/basics/ , but the spec is likely t have changed a bit since.
Most current browsers support this API, with the notable exception of IE11: http://caniuse.com/#feat=eventsource
it is possible to write a java applet which can work as a network server. Once the applet has successfully started, it can report its port and ip number back to the remote server.
Then your server can send messages to the client server any time it feels like. Your java applet can then hand the message off to javascript, or do whatever else.
This method requires java plugin support however, which is far from universal.