views:

378

answers:

6

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

+5  A: 

HTTP protocol is stateless by design. The only one way to achieve this is to implement client-side polling via AJAX.

Vitaliy Liptchinsky
+5  A: 

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.

Darrell Brogdon
And there's a jQuery plugin for it described in this thread: http://stackoverflow.com/questions/136012/comet-and-jquery/137064#137064
Peter Rowell
+1  A: 

Pushlets?

brownstone
A: 

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.

Breton
A: 

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.

laura
Is that specific to the case of java on the server side?
dreeves
DWR is java-specific, but I believe the techniques themselves can be implemented in any language, I do not see any reason why this could not be done
laura
+1  A: 

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 http://stackoverflow.com/questions/531001/running-server-side-function-as-browser-closes/531007#531007 for info on keeping track of browser disconnects, ie, server-side action on client disconnect.

Bee
This seems to work fine for me on Firefox but on Safari and Chrome it shows the little spinny icon forever and never thinks it's finished loading the page. Any idea what's going on there? (Should I make this a separate StackOverflow question?)
dreeves