How to Improve the Long Poll Capabilities Using PHP and AJAX - php

I have implemented the long polling successfully using normal Apache server, PHP, AJAX and Javascript. I don't use the Jquery to communicate with the server.
The problem is that the Apache server capabilities are limited, the server is not able to serve more than 5 browser tabs.
I wonder if there is any customization for the Apache or for the PHP to make them handle more concurrent connections? Or if there is any new/smart technique to do that? What are the maximum threads can be handled by a robust web server specialized in long polling?
I am not interested in the Web Sockets because of the browsers compatibility. I need something easy and robust into PHP. What Facebook are doing? I wonder how can they handle all the dynamic updates for million of users! What products/techniques they use?
A sample of my code:
srv_polling.php
<?php
function getResults(){..... return result;}
// recursive function inside the server
function hasResultChanged($old,$timeStart){
// to avoid server timeout (in seconds) in case no change for results
if(round(abs(time() - $timeStart) / 60*60,2) > 50)
return;
$new = getResults();
if($new != $old) // get back to browser
return true;
else{
$old = getResults();
sleep(2);
return $hasResultChanged($old,$timeStart);
}
}
$timeStart = time();
$old = $getResults();
sleep(2);
$hasResultChanged($old,$timeStart);
?>
// Javascript code to be executed at browser end
alert('Result has changed');
// Send AJAX request again to same page(srv_polling.php):
ajax.call({......})
Thank you for your hints! Greatly appreciated.

I am using this in my project
public function getLPollData($user, $handlerName) {
set_time_limit (600);
date_default_timezone_set('Europe/Berlin');
$counterEnd = (int)$_REQUEST["counterEnd"];
$counterStart = (int)$_REQUEST["counterStart"];
$this->expireNotifications($counterStart, $counterEnd);
$secCount = IDLE_WAIT;
do {
sleep(IDLE_TIME);
$updates = $this->fetchAllNotifications($counterEnd);
} while (!$updates && ($secCount--)>0);
if($updates){
}
header("HTTP/1.0 200");
return sprintf ('{"time" : "%s", "counter" : "%d", start : %d, data : %s}'
, date('d/m H:i:s'), $counterEnd,$counterStart,json_encode($updates));
}
Its combination of IDLE_WAIT & IDLE_TIME (10*3=~30 secs).
But i dont think your problem is on server side, if you are opening 5-6 connections from a browser, then remember each browser has limitation on how many active connections it can have to some particular domain, at a time. try diff browser or better diff machines, max two tabs in one browser.

Related

ajax continuous update php causing server to block my ip

I'm using an Ajax function with a call to itself to update the information continuously. But I let the script run for a while and then the server blocked my IP because it thought I was flooding it or something like that, I don't know. Anyway, I wonder if there's another way to do this more properly. Here's my code:
Ajax function:
function update_cart()
{
if (window.XMLHttpRequest)
var http = new XMLHttpRequest();
else
var http = new ActiveXObject('Microsoft.XMLHTTP');
http.onreadystatechange=function()
{
if ((http.readyState == 4) && (http.status == 200))
{
id('cart_quantity').innerHTML = parseInt(http.responseText);
setTimeout('update_cart()', 1000);
}
}
http.open('GET', actual_path+'fetch_cart_quantity.php', true);
http.setRequestHeader("X-Requested-With", "XMLHttpRequest");
http.send();
}
PHP script:
<?php
if($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest')
{
header('Location: ./');
exit();
}
session_start();
include '../include/config.php';
include '../include/db_handler.php';
include '../include/cart_handler.php';
$cart = get_cart_quantity($_SESSION['cart_id']);
if ($cart == NULL) $cart = 0;
echo $cart;
?>
Thanks in advance for your help. Sorry that my English is not very good.
You have a couple of options here as I stated in my comment.
Basically the first is to chill out with the querying. You don't need to long poll such a thing. Turn down the querying to once every 5 mins or just whenever there is an action.
You can also build a simple comet server to do a push pull type thing when ever updates are "pushed" down from the server. There is a pre-built one called APE: http://www.ape-project.org/
Also node.js can handle this sort of thing for you.
Also you should probably look into your server setup, sounds kinda weird that your sever is blocking it's own IP address/domain...
Probaly, but i seriously think that querying your server every second is totally innecesary and also a waste of resources (unless you have very compulsive customers), making your script to query your server every minute or so is better and may work even better in the long term if you have several customers using this application from the same server.
If you really think is necessary to have this feature, a good approach will be using Push notifications, more info can be found here: PHP - Push Notifications, here: Push notification to the client browser and here: Push notifications from server to user with PHP/JavaScript.
Why don't you just update the cart when the user performs an action.
Such as 'Add item to shopping cart'?
That way you'd only call the server when it's actually needed.

Webbased chat in php without using database or file

I am trying to implement a realtime chat application using PHP . Is it possible to do it without using a persistent data storage like database or file . Basically what I need is a mediator written in PHP who
accepts messages from client browsers
Broadcasts the message to other clients
Forgets the message
You should check out Web Sockets of html5. It uses two way connection so you will not need any database or file. Any chat message comes to the server will directly sent to the other users browser without any Ajax call. But you need also to setup web socket server.
Web sockets are used in many real time applications as well. I am shortly planing to write full tutorial on that. I will notify you.
Just tried something I had never done before in response to this question. Seemed to work but I only tested it once. Instead of using a Socket I had an idea of using a shared Session variable. Basically I forced the Session_id to be the same value regardless of the user therefore they are all sharing the same data. From a quick test it seems to work. Here is what I did:
session_id('12345');
session_start();
$session_id = session_id();
$_SESSION['test'] = $_SESSION['test'] + 1;
echo "session: {$session_id} test: {$_SESSION['test']} <br />";
So my thought process was that you could simply store the chat info in a Session variable and force everyone regardless of who they are to use a shared session. Then you can simply use ajax to continually reload the current Session variable, and use ajax to edit the session variable when adding a message. Also you would probably want to set the Session to never expire or have a really long maxlifetime.
As I said I just played around with this for a few minutes to see if it would work.
You will want to use Sockets. This article will cover exactly what you want to do: http://devzone.zend.com/209/writing-socket-servers-in-php/
When I tried to solve the same problem, I went with Nginx's Push Module. I chose to go this way since I had to support older browsers (that usually won't support WebSockets) and had no confidence in setting up an appropriate solution like Socket.io behind a TCP proxy.
The workflow went like this:
The clients connect through long-polling to my /subscriber location, which is open to all.
The /publisher location only accepts connections from my own server
When a client subscribes and talks, it basically just asks a PHP script to handle whatever data is sent.
This script can do validation, authorization, and such, and then forwards (via curl) the message in a JSON format to the /publisher.
Nginx's Push Module handles sending the message back to the subscribers and the client establishes a new long-polling connection.
If I had to do this all over again, then I would definitely go the Socket.io route, as it has proper fallbacks to Comet-style long-polling and has great docs for both Client and Server scripts.
Hope this helps.
If you have a business need for PHP, then adding another language to the mix just means you then have two problems.
It is perfectly possible to run a permanent, constantly-running daemonised PHP IRCd server: I know, because I've done it, to make an online game which ran for years.
The IRC server part I used is a modified version of WaveIRCd:
http://sourceforge.net/projects/waveircd/
I daemonised it using code I made available here:
http://www.thudgame.com/node/254
That code might be overkill: I wrote it to be as rugged as I could, so it tries to daemonise using PHP's pcntl_fork(), then falls back to calling itself recursively in the background, then falls back to perl, and so on: it also handles the security restrictions of PHP's safe mode in case someone turns that on, and the security restrictions imposed by being called through cron.
You could probably strip it down to just a few lines: the bits with the comments "Daemon Rule..." - follow those rules, and you'll daemonize your process just fine.
In order to handle any unexpected daemon deaths, etc, I then ran that daemoniser every minute through cron, where it checked to see if the daemon was already running, and if so either quietly died, or if the daemon was nonresponsive, killed it and took its place.
Because of the whole distributed nature of IRC, it was nicely rugged, and gave me a multiplayer browser game with no downtime for a good few years until bit-rot ate the site a few months back. I should try to rewrite the front end in Flash and get it back up again someday, when I have time...
(I then ran another daemonizer for a PHP bot to manage the game itself, then had my game connect to it as a java applet, and talk to the bot to play the game, but that's irrelevant here).
Since WaveIRCd is no longer maintained, it's probably worth having a hunt around to find if anyone else has forked the project and is supporting it.
[2012 edit: that said, if you want your front end to be HTML5/Javascript, or if you want to connect through the same port that HTTP connects through, then your options are more limited than when using Flash or Java. In that case, take the advice of others, and use "WebSockets" (poor support in most current browsers) or the "Socket.io" project (which uses WebSockets, but falls back to Flash, or various other methods, depending what the browser has available).
The above is for situations where your host allows you to run a service on another port. In particular, many have explicit rules in their ToS against running an IRCd.]
[2019 edit: WebSockets are now widely supported, you should be fine using them. As a relevant case study, Slack is written in PHP (per https://slack.engineering/taking-php-seriously-cf7a60065329), and for some time supported the IRC protocol, though I believe that that has since been retired. As its main protocol, it uses an API based on JSON over WebSockets (https://api.slack.com/rtm). This all shows that a PHP IRCd can deliver enterprise-level performance and quality, even where the IRC protocol is translated to/from another one, which you'd expect to give poorer performance.]
You need to use some kind of storage as a buffer. It IS plausable not to use file or db (which also uses a file). You can try using php's shared memory functions, but I don't know any working solution so you'll have to do it from scratch.
Is it possible to do it without using a persistent data storage like
database or file?
It is possible but you shouldn't use. Database or file based doesn't slows down chat. It will be giving additional security to your chat application. You can make web based chat using ajax and sockets without persistent data.
You should see following posts:
Is database based chat room bad idea?
Will polling from a SQL DB instead of a file for chat application increase performance?
Using memcached as a database buffer for chat messages
persistent data in php question
https://stackoverflow.com/questions/6569754/how-can-i-develop-social-network-chat-without-using-a-database-for-storing-the-c
File vs database for storage efficiency in chat app
PHP is not a good fit for your requirements (in a normal setup like apache-php, fastcgi etc.), because the PHP script gets executed from top to bottom for every request and cannot maintain any state between the requests without the use of external services or databases/files (Except e.g. http://php.net/manual/de/book.apc.php, but it is not intended for implementing a chat and will not scale to multiple servers.)
You should definitely look at Node.js and especially the Node.js module Socket.IO (A Websocket library). It's incredibly easy to use and rocks. Socket.IO can also scale to multiple chat servers with an optional redis backend, which means it's easier to scale.
Trying to use $_SESSION with a static session id as communication channel is not a solution by the way, because PHP saves the session data into files.
One solution to achieving this is by writing a PHP socket server.
<?php
// Set time limit to indefinite execution
set_time_limit (0);
// Set the ip and port we will listen on
$address = '192.168.0.100';
$port = 9000;
$max_clients = 10;
// Array that will hold client information
$clients = Array();
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port) or die('Could not bind to address');
// Start listening for connections
socket_listen($sock);
// Loop continuously
while (true) {
// Setup clients listen socket for reading
$read[0] = $sock;
for ($i = 0; $i < $max_clients; $i++)
{
if ($client[$i]['sock'] != null)
$read[$i + 1] = $client[$i]['sock'] ;
}
// Set up a blocking call to socket_select()
$ready = socket_select($read,null,null,null);
/* if a new connection is being made add it to the client array */
if (in_array($sock, $read)) {
for ($i = 0; $i < $max_clients; $i++)
{
if ($client[$i]['sock'] == null) {
$client[$i]['sock'] = socket_accept($sock);
break;
}
elseif ($i == $max_clients - 1)
print ("too many clients")
}
if (--$ready <= 0)
continue;
} // end if in_array
// If a client is trying to write - handle it now
for ($i = 0; $i < $max_clients; $i++) // for each client
{
if (in_array($client[$i]['sock'] , $read))
{
$input = socket_read($client[$i]['sock'] , 1024);
if ($input == null) {
// Zero length string meaning disconnected
unset($client[$i]);
}
$n = trim($input);
if ($input == 'exit') {
// requested disconnect
socket_close($client[$i]['sock']);
} elseif ($input) {
// strip white spaces and write back to user
$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
socket_write($client[$i]['sock'],$output);
}
} else {
// Close the socket
socket_close($client[$i]['sock']);
unset($client[$i]);
}
}
} // end while
// Close the master sockets
socket_close($sock);
?>
You would execute this by running it through command line and would always have to run for your PHP clients to connect to it. You could then write a PHP client that would connect to the socket.
<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
You would have to use some type of ajax to call with jQuery posting the message to this PHP client.
http://devzone.zend.com/209/writing-socket-servers-in-php/
http://php.net/manual/en/function.fsockopen.php
Better use a node.js server for this. WebSockets aren't cross-browser nowadays (except socket.io for node.js that works perfect)
in short answer, you can't.
the current HTTP/HTML implementation doesn't support the pushstate so the algorithm of your chat app should follow :
A: sent message
B,C,D: do while a new message has been sent get this message.
so the receivers always have to make a new request and check if a new message has been sent. (AJAX Call or something similar )
so always there are a delay between the sent event and the receive event.
which means the data must be saved in something global, like db or file system.
take a look for :
http://today.java.net/article/2010/03/31/html5-server-push-technologies-part-1
You didn't say it had to all be written it PHP :)
Install RabbitMQ, and then use this chat implementation built on top of websockets and RabbitMQ.
Your PHP is pretty much just 'chat room chrome'. It's possible most of your site would fit within the 5 meg limit of offline HTML5 content, and you have a very flexible (and likely more robust than if you did it yourself) chat system.
It even has 20 messages of chat history if you leave the room.
https://github.com/videlalvaro/rabbitmq-chat
If You need to use just PHP, then You can store chat messages in session variables, session could be like object, storing a lot of information.
If You can use jQuery then You could just append paragraph to a div after message has been sent, but then if site is refreshed, messages will be gone.
Or combining, store messages in session and update that with jQuery and ajax.
Try looking into socket libraries like ZeroMQ they allow for instant transport of the message, and are quicker than TCP, and is realtime. Their infrastructure allows for instant data send between points A and B, without the data being stored anywhere first (although you can still choose to).
Here's a tutorial for a chat client in ZeroMQ

Options to lessen database open connection?

I have a free application that is very used and I get around 500 to 1000 concurrent users from time to time.
This application is a desktop application that will communicate with my website API to receive data every 5 ~ 15 minutes as well as send back minimum data about 3 selects top every 15 minutes.
Since users can turn the application on and off as they wish the timer for each one of them to query my API may vary and as such I have been hitting the max connection limit available for my hosting plan.
Not wanting to upgrade it for financial matter as well as because it is a non-profitable application for the moment I am searching for other options to reduce the amount of connections and cache some information that can be cached.
The first thing that came to my mind was to use FastCGI with Perl I have tested it for some time now and it seems to work great but I have to problems while using it:
if for whatever reason the application goes idle for 60 the
server kills it and for the next few requests it will reply with
error 500 until the script is respawned which takes about 3+ minutes
(yes it takes that much I have tried my code locally on my own test
server and it comes up instantly so I am sure it is a server issue
of my hosting company but they don't seem like wanting to resolve
it).
the kill timeout which is set to 300 and will kill/restart the
script after that period which would result on the above said at 1)
about the respawn of the script.
Given that I am now looking for alternatives that are not based on FastCGI if there is any.
Also due to the limitations of the shared host I can't make my own daemon and my access to compile anything is very limited.
Are there any good options that I can archive this with either Perl or PHP ?
Mainly reduce the database open connections to a minimum and still be able to cache some select queries for returning data... The main process of the application is inserting/updating data anyway so there inst much to cache.
This was the simple code I was using for testing it:
#!/usr/bin/perl -w
use CGI::Simple; # Can't use CGI as it doesn't clear the data for the
# next request haven't investigate it further but needed
# something working to test and using CGI::Simples was
# the fastest solution found.
use DBI;
use strict;
use warnings;
use lib qw( /home/my_user/perl_modules/lib/perl/5.10.1 );
use FCGI;
my $dbh = DBI->connect('DBI:mysql:mydatabase:mymysqlservername',
'username', 'password',
{RaiseError=>1,AutoCommit=>1}
) || die &dbError($DBI::errstr);
my $request = FCGI::Request();
while($request->Accept() >= 0)
{
my $query = new CGI::Simple;
my $action = $query->param("action");
my $id = $query->param("id");
my $server = $query->param("server");
my $ip = $ENV{'REMOTE_ADDR'};
print $query->header();
if ($action eq "exp")
{
my $sth = $dbh->prepare(qq{
INSERT INTO
my_data (id, server) VALUES (?,INET_ATON(?))
ON DUPLICATE KEY UPDATE
server = INET_ATON(?)});
my $result = $sth->execute($id, $server, $server)
|| die print($dbh->errstr);
$sth->finish;
if ($result)
{
print "1";
}
else
{
print "0";
}
}
else
{
print "0";
}
}
$dbh->disconnect || die print($DBI::errstr);
exit(0);
sub dbError
{
my ($txt_erro) = #_;
my $query = new CGI::Simple;
print $query->header();
print "$txt_erro";
exit(0);
}
Run a proxy. Perl's DBD::Proxy should fit the bill. The proxy server shouldn't be under your host's control, so its 60-???-of-inactivity rule shouldn't apply here.
Alternatively, install a cron job that runs more often than the FastCGI timeout, simply to wget some "make activity" page on your site, and discard the output. Some CRMs do this to force a "check for updates" for example, so it's not completely unusual, though somewhat of an annoyance here.
FWIW, you probably want to look at CGI::Fast instead of CGI::Simple to resolve your CGI.pm not dealing in the expected manner with persistent variables...

PHP Singleton class for all requests

I have a simple problem. I use php as server part and have an html output. My site shows a status about an other server. So the flow is:
Browser user goes on www.example.com/status
Browser contacts www.example.com/status
PHP Server receives request and ask for stauts on www.statusserver.com/status
PHP Receives the data, transforms it in readable HTML output and send it back to the client
Browser user can see the status.
Now, I've created a singleton class in php which accesses the statusserver only 8 seconds. So it updates the status all 8 seconds. If a user requests for update inbetween, the server returns the locally (on www.example.com) stored status.
That's nice isn't it? But then I did an easy test and started 5 browser windows to see if it works. Here it comes, the php server created a singleton class for each request. So now 5 Clients requesting all 8 seconds the status on the statusserver. this means I have every 8 second 5 calls to the status server instead of one!
Isn't there a possibility to provide only one instance to all users within an apache server? That would be solve the problem in case 1000 users are connecting to www.example.com/status....
thx for any hints
=============================
EDIT:
I already use a caching on harddrive:
public function getFile($filename)
{
$diff = (time()-filemtime($filename));
//echo "diff:$diff<br/>";
if($diff>8){
//echo 'grösser 8<br/>';
self::updateFile($filename);
}
if (is_readable($filename)) {
try {
$returnValue = #ImageCreateFromPNG($filename);
if($returnValue == ''){
sleep(1);
return self::getFile($filename);
}else{
return $returnValue;
}
} catch (Exception $e){
sleep(1);
return self::getFile($filename);
}
} else {
sleep(1);
return self::getFile($filename);
}
}
this is the call in the singleton. I call for a file and save it on harddrive. but all the request call it at same time and start requesting the status server.
I think the only solution would be a standalone application which does an update every 8 seconds on the file... All request should just read the file and nomore able to update it.
This standalone could be a perl script or something similar...
Php requests are handled by different processes and each of them have a different state, there isn't any resident process like in other web development framework. You should handle that behavior directly in your class using for instance some caching.
The method which query the server status should have this logic
public function getStatus() {
if (!$status = $cache->load()) {
// cache miss
$status = // do your query here
$cache->save($status); // store the result in cache
}
return $status;
}
In this way only one request of X will fetch the real status. The X value depends on your cache configuration.
Some cache library you can use:
APC
Memcached
Zend_Cache which is just a wrapper for actual caching engines
Or you can store the result in plain text file and on every request check for the m_time of the file itself and rewrite it if more than xx seconds are passed.
Update
Your code is pretty strange, why all those sleep calls? Why a try/catch block when ImageCreateFromPNG does not throw?
You're asking a different question, since php is not an application server and cannot store state across processes your approach is correct. I suggest you to use APC (uses shared memory so it would be at least 10x faster than reading a file) to share status across different processes. With this approach your code could become
public function getFile($filename)
{
$latest_update = apc_fetch('latest_update');
if (false == $latest_update) {
// cache expired or first request
apc_store('latest_update', time(), 8); // 8 is the ttl in seconds
// fetch file here and save on local storage
self::updateFile($filename);
}
// here you can process the file
return $your_processed_file;
}
With this approach the code in the if part will be executed from two different processes only if a process is blocked just after the if line, which should not happen because is almost an atomic operation.
Furthermore if you want to ensure that you should use something like semaphores to handle that, but it would be an oversized solution for this kind of requirement.
Finally imho 8 seconds is a small interval, I'd use something bigger, at least 30 seconds, but this depends from your requirements.
As far as I know it is not possible in PHP. However, you surely can serialize and cache the object instance.
Check out http://php.net/manual/en/language.oop5.serialization.php

How to get my client to ping server?

I'm trying to figure a way where my clients can ping my server via php, and then retrieve the results into format like this "15 MS".
I ended up finding a way where servers can ping servers. However I want to be able to have the remote user somehow ping the server, or maybe have the server ping the client possibly?
function track($host, $port, $timeout) {
$firstTime = microtime(true);
$sock = fSockOpen($host, $port, $errno, $errstr, $timeout);
if (!$sock) {
echo "<b>Offline</b>";
}
$secondTime = microtime(true);
$ping = round((($secondTime - $firstTime) * 1000), 0);
echo $ping." ms";
}
track($_SERVER["REMOTE_ADDR"], 80, 10);
I tried this function, where I'd get the server to ping the client to see the response time between the client/server.
fsockopen() [function.fsockopen]: unable to connect to XXXXXXXXXXX:80
I'm trying to figure a way where my clients can ping my server via php
Why? What's the value in knowing this information? Although I noted that Emil's answer didn't address the question, it might address the problem - the time it takes for an ICMP packet to go to a server and come back will be different from the time taken to complete a TCP handshake on port 80 across the internet (they should be roughly the same on a LAN provided the webserver is not saturated).
If you want to get good information about RTT times, then a better solution would be to use a network monitoring tool / software. PastMon is an obvious candidate.
If you really must send a ping from the client, then you'd need to do this using a java applet / flash / activeX (assuming that these have the low-level TCP stack access required to carry out a ping).
C.
What makes you think clients are going to reliably respond to ICMP echo requests?
A better solution would be to write a client-side Java applet (or JavaScript?) to ping your server.
Remember, security restrictions will limit both languages to only communicate back to their origin server. You won't be able to allow your users to ping a server besides your own... but that doesn't appear to be an issue in your case.
You have to do this in JavaScript. The client cannot run PHP at all, and your attempt to ping the client will not work when their firewall blocks requests from the outside (which is often the case).
Build a "ping" function in JS which fetches a page a few times by AJAX. This example is built upon the jQuery framework:
Web page/JS
<script src="jquery-1.4.2.min.js"></script>
<script>
var global_runs = 0;
function ping(data) {
var op = "";
if(global_runs == 0) {
op = "start";
}else if(global_runs == 3){
op = "end";
}else if(global_runs > 3) {
return;
}
global_runs++;
$.post("ping.php", {op: op}, ping);
if(data != null) {
$("#time").text(data + " MS");
}
}
$(document).ready(function(){
//Start pinging
ping();
});
</script>
<p id="time">Time will be here</p>
ping.php
<?php
session_start();
if($_POST['op'] == 'start' || !isset($_SESSION['start'])) {
$_SESSION['start'] = microtime(true);
$_SESSION['runs'] = 0;
}else{
$_SESSION['runs']++;
$now = microtime(true);
$time = $now - $_SESSION['start'];
echo ($time / $_SESSION['runs']) * 1000; //milliseconds
}
?>
I don't really make use of the end op here, but it can be used to let the server now that this is the last ping request. Note that this code trusts the client, which means you may need some extra work on the security on the serverside (maybe take away the whole notion of "ops" from the serverside and ust send the pings?). Also, you probably want different counters for each page, maybe identified by some token that you return in the first request.
Also note that this is depending on HTTP and CPU latency as well, not just the network, but I think it's as good as you can get it.

Categories