views:

1416

answers:

8

I run a couple of game tunnelling servers and would like to have a page where the client can run a ping on all the servers and find out which is the most responsive. As far as I can see there seems to be no proper way to do this in JavaScript, but I was thinking, does anybody know of a way to do this in flash or some other client browser technology maybe?

+2  A: 

If you are talking about running something client side, I am not sure this is possible due to security reasons.

Maybe your best bet would be a java applet - but again this needs to be checked against local security policy.

If I try to think about some hack in JS to do this, maybe you can try to send an async request with a callback function which measures the milliseconds it took - but this is just off the top of my head.

Yuval A
I know one way I can do it is by sending a HEAD request, but I was more hoping that there is a way to do it using flash?
Mladen Mihajlovic
Java applets are only allowed to contact their originating server.
Magnar
Applets with more permissive security are allowed if they are signed and accepted. Or at least they used to be. The last time I saw one was with Netscape 4.
Zan Lynx
+10  A: 

Most applet technology, including Javascript, enforces a same-origin policy. It may be possible to dynamically add DOM elements, such as images, and collect timing information using the onload event handler.

Psuedo-code

for (server in servers) {
  var img = document.createElement('IMG');
  server.startTime = getCurrentTimeInMS();
  img.onload=function() { server.endTime = getcurrentTimeInMS(); }
  img.src = server.imgUrl;
}

Then wait an appropriate time and check the timing for each server object. Repeat as needed and compute averages if you want. I'm not sure what kind of accuracy you can expect.

Disadvantages:

  • You are probably using the wrong tool for the job. A browser is not equipped for this sort of application.
  • It's probably quite inaccurate.
  • If the resource you request is cached it won't give you the results you want, but you can work around that by changing the url each time.
  • This is bandwidth-intensive compared to a normal ping. Make the image tiny, such as a spacer.gif file.
  • The timing depends not only on the latency of the remote server but the bandwidth of that server. This may be a more or less useful measure but it's important to note that it is not simply the latency.
  • You need to be able to serve HTTP requests from the various servers and, crucially, each server should serve the exact same resource (or a resource of the same length). Conditions on the server can affect the response time, such as if one server is compressing the data and another isn't.
Mr. Shiny and New
Use new Image() instead of creating a whole DOM-object.
Georg
@gs: Is there an advantage to using new Image()?
Mr. Shiny and New
The problem with all these solutions which include downloading something is that it's really testing the speed of the web server, and not the latency of the network connection. So it's not really a true reflection, especially for my needs which are for very specific network latency speeds.
Mladen Mihajlovic
@Mladen Mihajlovic: This is the limitation of the technology you are using. Most applet technology doesn't allow you to make arbitrary TCP/UDP connections to arbitrary servers. That's what you'd need.
Mr. Shiny and New
It seems that it's possible in Flash (see answer below). Only problem is I don't know flash at all :)
Mladen Mihajlovic
+1  A: 

The problem with 'file pings' is that you would evaluate the http server response whereas your target resource for the games you serve may have a very different behavior and thereby a different latency.

Just an idea out of the blue, maybe even unrealistic depending on the actual context: but, wouldn't it be interesting to make a server script based on a short sequence of tasks typically executed by the servers during the gameplay (e.g. opening a RTMP connection, retrieving an information, sending it back). Depending on the total number of servers, you could almost opening them simultaneously and define the first response as winner (subtracting the time your client requires independently to process each query).

Of course this is a quite expensive method server-side-speaking, but at least you would hopefully get a reliable result (server and network latencies summed up). Even if it takes a couple seconds to evaluate, this would be the matter of a fraction of the total enjoyable game-play.

Theo.T
+5  A: 

Before the call to the server, record the Javascript time:

var startTime = new Date();

Load an image from the server:

var img = new Image()
img.onload = function() {
    // record end time
}
img.src = "http://server1.domain.com/ping.jpg";

As soon as the request is finished, record the time again. (Given of course that the request didn't time out.)

var endTime = new Date();

Your ping in milliseconds is:

var ping = endTime. getTime() - startTime.getTime();
Georg
+3  A: 

All you really need is the time from the connection start, to the time of the first readystate change...

function getPing() {
  var start;
  var client = getClient(); // xmlhttprequest object
  client.onreadystatechange = function() {
    if (client.readyState > 0) {
      pingDone(start); //handle ping
      client.onreadystatechange = null; //remove handler
    } 
  }

  start = new Date();
  client.open("HEAD", "/ping.txt"); //static file
  client.send();
}

function pingDone(start) {
  done = new Date();
  ms = done.valueOf() - start.valueOf();
  alert(ms + "ms ping time");
}

function getClient() {
  if (window.XMLHttpRequest)
    return new XMLHttpRequest();

  if (window.ActiveXObject)
    return new ActiveXObject('MSXML2.XMLHTTP.3.0');

  throw("No XMLHttpRequest Object Available.");
}
Tracker1
This will only work if you are pinging the server hosting the webpage, and not for pinging other servers.
Mr. Shiny and New
+2  A: 

It's not that hard to measure server response time in Flash.

Flash must ask for a policy file before accessing remote servers. The default location for such policy file is at the root folder of the server: /crossdomain.xml

(You can easily find information about the crossdomain file format)

Since such file is needed anyway, why not use it to measure server response time? Load the file itself instead of an image and measure the time it took using getTimer() .

This will give you a good estimate on HTTP connections.

But if you're dealing with game servers, you might want to directly check the speed of the TCP connection. To do that you'll need to use the flash.net.Socket You'll also have to ask for a policy file first by running: Security.loadPolicyFile("xmlsocket://server.domain.com:5342");

Where 5342 represents your server's port number where it should respond with the proper XML policy string. After making the socket connection, any request/response will let you measure different server response times.

Eliram
This sounds quite promising. Do you have some code, or an example flash "applet" I can see? I'm not an actionscript programmer myself.
Mladen Mihajlovic
A: 
Ates Goral
+2  A: 

Keep in mind that the latency is going to be at least twice of what you'd see for a ping if you end up making a TCP query to measure latency, because you'll need the three way handshake and the termination packet at minimum (two round trips rather than one). If you make HTTP requests, try to keep the headers to a minimum. A long enough header (due to a chatty server, or cookies etc on the client) can add additional round trips into the mix, throwing off your measurements.

Peter Burns