我运行了几个游戏隧道服务器,并希望有一个页面,客户端可以在其中对所有服务器运行 ping 并找出响应速度最快的服务器。据我所知,在 JavaScript 中似乎没有合适的方法来执行此操作,但我在想,是否有人知道在 Flash 或其他一些客户端浏览器技术中执行此操作的方法?
9 回答
大多数小程序技术,包括 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 请求提供服务,并且至关重要的是,每个服务器应该提供完全相同的资源(或相同长度的资源)。服务器上的条件会影响响应时间,例如一台服务器正在压缩数据而另一台没有。
在调用服务器之前,记录下 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();
您真正需要的只是从连接开始到第一次就绪状态更改的时间......
函数 getPing() { 变量开始; var 客户端 = getClient(); // xmlhttp请求对象 client.onreadystatechange = function() { if (client.readyState > 0) { pingDone(开始);//处理ping 客户端.onreadystatechange = null; //删除处理程序 } } 开始 = 新日期(); client.open("HEAD", "/ping.txt"); //静态文件 客户端.send(); } 功能 pingDone(开始) { 完成 = 新日期(); ms = done.valueOf() - start.valueOf(); alert(ms + "ms ping 时间"); } 函数 getClient() { 如果(窗口.XMLHttpRequest) 返回新的 XMLHttpRequest(); 如果(窗口。ActiveXObject) 返回新的 ActiveXObject('MSXML2.XMLHTTP.3.0'); throw("没有可用的 XMLHttpRequest 对象。"); }
这是一种<iframe>
方法:
(来源:magnetiq.com)
<table>
创建一个包含两列的表(不一定是字面意义上的)。第一列将包含服务器的名称(可能还有指向它们的链接)。第二列具有从各个服务器加载探测文档的 iframe。每个探测文档都会在初始获取请求上执行此操作:
- 获取当前系统时间
- 在将系统时间作为查询参数传递的同时,重定向 (302) 到第二个探测文档
- 第二个探测文档读取当前系统时间,根据传递给它的初始读数计算增量,并以大字体显示。此增量将是服务器以重定向响应响应客户端所用的时间加上客户端向重定向目标发出第二次请求所用的时间。它不完全是“ping”,但它是客户端与每个服务器的相对延迟的可比较度量。实际上,这是从服务器到客户端的“反向 ping”。
您将在不违反同域策略的情况下使用 iframe,因为根本没有尝试操纵 iframe 内容。玩家将简单地用他/她的眼睛看到这些值,而您将依赖于用户浏览数字并单击最有意义的服务器链接。
任何发出 HTTP 请求的东西(就像这里的大多数答案一样)通常测量的延迟至少是正常 ping 看到的延迟的两倍,因为您至少需要三向握手和终止数据包(两次往返而不是一次)。如果您发出 HTTP 请求,请尽量减少标头。足够长的标头(由于聊天服务器或客户端上的 cookie 等)可能会增加额外的往返行程,从而影响您的测量结果。
正如 Cherona 所指出的,如果您已经与服务器建立了活动的 HTTP 2 连接,或者如果服务器使用 HTTP 3,那么情况可能并非如此。
最准确的选择是打开到每个服务器的 websocket 连接,并测量发送微小消息和接收微小响应所需的时间(在建立连接之后)。
如果您正在谈论在客户端运行某些东西,由于安全原因,我不确定这是否可行。
也许你最好的选择是一个 java 小程序——但这需要再次检查本地安全策略。
如果我尝试在 JS 中考虑一些 hack 来做到这一点,也许你可以尝试发送一个带有回调函数的异步请求,该函数测量它所花费的毫秒数——但这只是我的想法。
在 Flash 中测量服务器响应时间并不难。
Flash 必须在访问远程服务器之前请求策略文件。此类策略文件的默认位置是服务器的根文件夹:/crossdomain.xml
(您可以轻松找到有关跨域文件格式的信息)
既然无论如何都需要这样的文件,为什么不使用它来测量服务器响应时间呢?加载文件本身而不是图像,并使用 getTimer() 测量它所花费的时间。
这将为您提供对 HTTP 连接的良好估计。
但如果您正在处理游戏服务器,您可能需要直接检查 TCP 连接的速度。为此,您需要使用 flash.net.Socket 您还必须首先通过运行请求策略文件: Security.loadPolicyFile("xmlsocket://server.domain.com:5342");
其中 5342 表示您的服务器的端口号,它应该使用正确的 XML 策略字符串进行响应。建立套接字连接后,任何请求/响应都会让您测量不同的服务器响应时间。
'file pings' 的问题在于您将评估 http 服务器响应,而您所服务的游戏的目标资源可能具有非常不同的行为,从而导致不同的延迟。
只是一个出乎意料的想法,根据实际情况甚至可能不切实际:但是,根据通常由服务器在游戏过程中执行的短任务序列(例如打开 RTMP)制作服务器脚本不是很有趣连接,检索信息,发回)。根据服务器的总数,您几乎可以同时打开它们并将第一个响应定义为获胜者(减去您的客户端独立处理每个查询所需的时间)。
当然,从服务器端来说,这是一种相当昂贵的方法,但至少你会希望得到一个可靠的结果(服务器和网络延迟的总和)。即使评估需要几秒钟,这也只是整个游戏乐趣的一小部分。
根据@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 变量接收初始时间减去最终时间。警报弹出窗口显示结果。