How to determine latency of a remote server through the browser

16,320

Solution 1

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.

Solution 2

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();

Solution 3

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.");
}

Solution 4

Here's an <iframe> approach:


(source: magnetiq.com)

Create a table (not necessarily in the literal <table> sense) with two columns. The first column will hold the name of servers (and possibly links to them). The second column has iframes that load probe documents from the respective servers. Each probe document does this on the initial fetch request:

  1. Get current system time
  2. Do a redirect (302) to a second probe document while passing the system time as a query parameter
  3. The second probe document reads the current system time, calculates the delta from the initial reading that was passed to it and just displays it in big fat letters. This delta will be the time it took for the server to respond to the client with a redirect response plus the time it took for the client to make the second request to the redirection target. It's not exactly a "ping" but it's a comparable measure of the client's relative latency with each server. In fact, it's a "reverse ping" from the server to the client.

You'd be using iframes without infringing the same-domain policy because there's no attempt at manipulating the iframe contents at all. The player will simply see the values with his/her own eyes and you'll rely on the user glancing at the numbers and clicking on the server link that makes the most sense.

Solution 5

Anything that makes an HTTP request (like most of the answers here) will generally measure a latency that's at least twice of what you'd see for a normal ping, 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.

As Cherona points out, if you already have an active HTTP 2 connection to the server, or if the server speaks HTTP 3, then this may not be the case.

The most accurate option would be to open a websocket connection to each server and measure the time it takes to send a tiny message and receive a tiny response (after the connection has been established).

Share:
16,320
Germán Martínez
Author by

Germán Martínez

.NET and PHP Developer. Creator of: TracExplorer (http://tracexplorer.devjavu.com/) Mamesaver (http://mamesaver.sf.net/)

Updated on June 05, 2022

Comments

  • Germán Martínez
    Germán Martínez almost 2 years

    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?

  • Germán Martínez
    Germán Martínez over 15 years
    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?
  • Magnar
    Magnar about 15 years
    Java applets are only allowed to contact their originating server.
  • Stefan
    Stefan about 15 years
    Use new Image() instead of creating a whole DOM-object.
  • Germán Martínez
    Germán Martínez about 15 years
    This sounds quite promising. Do you have some code, or an example flash "applet" I can see? I'm not an actionscript programmer myself.
  • Mr. Shiny and New 安宇
    Mr. Shiny and New 安宇 about 15 years
    @gs: Is there an advantage to using new Image()?
  • Mr. Shiny and New 安宇
    Mr. Shiny and New 安宇 about 15 years
    This will only work if you are pinging the server hosting the webpage, and not for pinging other servers.
  • Zan Lynx
    Zan Lynx about 15 years
    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.
  • Germán Martínez
    Germán Martínez about 15 years
    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.
  • Mr. Shiny and New 安宇
    Mr. Shiny and New 安宇 about 15 years
    @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.
  • Cherona
    Cherona almost 4 years
    This isn't true for HTTP2 and HTTP3
  • Peter Burns
    Peter Burns almost 4 years
    Good point! Edited to add mention of HTTP 2, HTTP 3, and websockets.