如何通过浏览器确定远程服务器的延迟

发布于 2024-07-13 19:15:45 字数 137 浏览 14 评论 0原文

我运行几个游戏隧道服务器,并希望有一个页面,客户端可以在所有服务器上运行 ping 并找出响应最快的服务器。 据我所知,在 JavaScript 中似乎没有正确的方法来做到这一点,但我在想,有人知道在 Flash 或其他客户端浏览器技术中做到这一点的方法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

杯别 2024-07-20 19:15:45

大多数小程序技术(包括 Javascript)都强制执行同源策略。 可以动态添加 DOM 元素(例如图像),并使用 onload 事件处理程序收集计时信息。

伪代码

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

然后等待适当的时间并检查每个服务器对象的计时。 根据需要重复并计算平均值(如果需要)。 我不确定您能期望什么样的准确性。

缺点:

  • 您可能使用了错误的工具来完成这项工作。 浏览器不适合此类应用程序。
  • 这可能是非常不准确的。
  • 如果您请求的资源被缓存,它不会给您想要的结果,但您可以通过每次更改 url 来解决这个问题。
  • 与普通 ping 相比,这是带宽密集型的。 使图像变小,例如 spacer.gif 文件。
  • 时间不仅取决于远程服务器的延迟,还取决于该服务器的带宽。 这可能是一个或多或少有用的衡量标准,但重要的是要注意它不仅仅是延迟。
  • 您需要能够为来自不同服务器的 HTTP 请求提供服务,最重要的是,每个服务器应该提供完全相同的资源(或相同长度的资源)。 服务器上的条件可能会影响响应时间,例如一台服务器是否正在压缩数据而另一台服务器则没有。

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.
苹果你个爱泡泡 2024-07-20 19:15:45

在调用服务器之前,记录 Javascript 时间:

var startTime = new Date();

从服务器加载图像:

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

请求完成后,再次记录时间。 (当然,前提是请求没有超时。)

var endTime = new Date();

您的 ping(以毫秒为单位)是:

var ping = endTime. getTime() - startTime.getTime();

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();
能怎样 2024-07-20 19:15:45

您真正需要的是从连接开始到第一次就绪状态更改的时间......

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

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.");
}
耶耶耶 2024-07-20 19:15:45

这是 方法:


(来源:magnetiq.com)

创建一个表(不一定从字面上的 意义上来说)有两列。 第一列将保存服务器的名称(可能还有指向它们的链接)。 第二列具有从相应服务器加载探测文档的 iframe。 每个探测文档在初始获取请求时执行以下操作:

  1. 获取当前系统时间
  2. 重定向 (302) 到第二个探测文档,同时将系统时间作为查询参数传递
  3. 第二个探测文档读取当前系统时间,计算与传递给它的初始读数并以大字体显示。 该增量将是服务器通过重定向响应响应客户端所花费的时间加上客户端向重定向目标发出第二个请求所花费的时间。 它并不完全是“ping”,而是客户端与每台服务器的相对延迟的可比较度量。 事实上,这是从服务器到客户端的“反向 ping”。

您使用 iframe 时不会违反同域策略,因为根本不会尝试操纵 iframe 内容。 玩家只需用自己的眼睛看到这些值,而您将依赖于用户浏览数字并单击最有意义的服务器链接。

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.

雪落纷纷 2024-07-20 19:15:45

任何发出 HTTP 请求(如此处的大多数答案)的延迟通常至少是正常 ping 的两倍,因为您至少需要三向握手和终止数据包(两次往返而不是一次)。 如果您发出 HTTP 请求,请尝试将标头保持在最低限度。 足够长的标头(由于服务器繁忙或客户端上的 cookie 等)可能会在混合中添加额外的往返行程,从而影响您的测量。

正如 Cherona 指出的那样,如果您已经与服务器建立了活动的 HTTP 2 连接,或者服务器使用 HTTP 3,那么情况可能并非如此。

最准确的选择是打开到每个服务器的 websocket 连接,并测量发送一条微小消息和接收一条微小响应所需的时间(在建立连接之后)。

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).

耳钉梦 2024-07-20 19:15:45

如果您正在谈论在客户端运行某些内容,由于安全原因,我不确定这是否可行。

也许您最好的选择是 Java 小程序 - 但这需要根据本地安全策略进行检查。

如果我尝试考虑一些 JS 中的 hack 来做到这一点,也许你可以尝试发送一个带有回调函数的异步请求,该函数测量它所花费的毫秒数 - 但这只是我的想法。

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.

云之铃。 2024-07-20 19:15:45

在 Flash 中测量服务器响应时间并不难。

Flash 在访问远程服务器之前必须请求策略文件。
这种策略文件的默认位置是服务器的根文件夹:/crossdomain.xml

(您可以轻松找到有关跨域文件格式的信息)

既然无论如何都需要这样的文件,为什么不使用它来测量服务器响应时间呢? 加载文件本身而不是图像,并使用 getTimer() 测量所需的时间。

这将为您提供有关 HTTP 连接的良好估计。

但如果您正在处理游戏服务器,您可能需要直接检查 TCP 连接的速度。 为此,您需要使用 flash.net.Socket
您还必须首先运行以下命令来请求策略文件:
Security.loadPolicyFile("xmlsocket://server.domain.com:5342");

其中 5342 代表服务器的端口号,服务器应使用正确的 XML 策略字符串进行响应。
建立套接字连接后,任何请求/响应都将让您测量不同的服务器响应时间。

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.

幸福不弃 2024-07-20 19:15:45

“文件 ping”的问题在于,您将评估 http 服务器响应,而您所服务的游戏的目标资源可能具有非常不同的行为,从而导致不同的延迟。

只是一个突然的想法,根据实际情况甚至可能不切实际:
但是,根据通常由服务器在游戏过程中执行的短任务序列(例如打开 RTMP 连接、检索信息、将其发回)来制作服务器脚本不是很有趣吗? 根据服务器总数,您几乎可以同时打开它们并将第一个响应定义为获胜者(减去客户端独立处理每个查询所需的时间)。

当然,对于服务器端而言,这是一种相当昂贵的方法,但至少您希望获得可靠的结果(服务器和网络延迟的总和)。 即使需要几秒钟来评估,这也只是整个游戏乐趣的一小部分。

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.

孤君无依 2024-07-20 19:15:45

根据@Mr. 的回复。 Shiny 和 @Georg Schölly ,一个完整且带注释的示例。

为了进行测试,只需按照相同的顺序复制下面的代码并将其粘贴到空的 .html、.php 或其他兼容文件中。

在开始获取之前,记录当前的Javascript时间。
使用new Date(),我们创建一个包含当前日期和时间的新日期对象。

<script type="text/javascript">

var startTime = new Date();

现在让我们创建一个 html 对象图像,仍然没有源,并将其归因于变量 img。

var img = new Image();

下一个扫描将源放入图像中。 .src 反映了 src html 属性。
重要的! 将您的 img.src 指向一个非常小且轻量级的图像文件,如果可能的话,任何小于 10KB 的文件。

为了防止缓存,在文件末尾的 .png 扩展名后面添加了一个随机参数。

var random_string = Math.random().toString();
img.src = "http://static.bbci.co.uk/frameworks/barlesque/5.0.0/orb/4/img/bbc-blocks-dark.png" + "?" + random_string;

现在我们可以调用我们的函数,该函数将在图像加载时运行,因为 .onload:

img.onload = function() {
    var endTime = new Date();
    var ping = endTime. getTime() - startTime.getTime();
    alert(img.src + " loaded in " + ping + " ms");
}
</script>

在函数内部我们有变量 endTime,它在源图像加载后接收日期时间。

最后,ping 变量接收初始时间减去最终时间。
警报弹出窗口显示结果。

Based on the responses of @Mr. Shiny and @Georg Schölly , a complete and commented example.

In order to test, just copy and paste the codes below in the same order, in a empty .html, .php or other compatible file.

Before start the get, record the current Javascript time.
Using new Date(), we create a new date object with the current date and time.

<script type="text/javascript">

var startTime = new Date();

Now let's create a html object image, still without source, and attribute it to the variable img.

var img = new Image();

The next spet is put a source in the image. The .src reflects the src html attribute.
Important! Point your img.src to a very small and lightweight image file, if possible anything less than 10KB.

To prevent cache a random parameter was added at the end of file, after the .png extension.

var random_string = Math.random().toString();
img.src = "http://static.bbci.co.uk/frameworks/barlesque/5.0.0/orb/4/img/bbc-blocks-dark.png" + "?" + random_string;

Now we may call our function which will run just when the image loads, because the .onload:

img.onload = function() {
    var endTime = new Date();
    var ping = endTime. getTime() - startTime.getTime();
    alert(img.src + " loaded in " + ping + " ms");
}
</script>

Inside the function we have the variable endTime that receives a date time after the source image was loaded.

Lastly, the ping variable receives the initial time minus the final time.
The alert popup shows the result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文