如何使用JavaScript ping IP地址

11
我想运行JavaScript代码以ping 4个不同的IP地址,然后检索这些ping请求的数据包丢失率和延迟,并在页面上显示它们。如何实现这个功能?

这个问题相关。 - Linus Kleen
应该查看上面的解决方案。相当不错。 - Jeffrey Tackett
9个回答

21

你无法从JS中实现这一点。你可以做的是:

 client --AJAX-- yourserver --ICMP ping-- targetservers

向你的服务器发出一个AJAX请求,然后由服务器代表你对目标服务器进行ping测试,并在AJAX结果中返回结果。

可能存在以下注意事项:

  • 这告诉您目标服务器是否可从您的服务器ping通,而不是从用户的客户端ping通
    • 因此,客户端将无法测试其LAN上的主机
    • 但如果存在,则不应让主机检查服务器内部网络上的主机
    • 某些主机可能会阻止来自某些主机但不是其他主机的流量
  • 需要限制每台机器的ping次数:
    • 避免AJAX请求超时
    • 一些站点操作员经常被频繁ping他们的站点所激怒
  • 资源
    • 长时间运行的HTTP请求可能会达到服务器的最大连接限制,请检查它有多高
    • 许多用户同时尝试ping可能会产生看起来可疑的流量(全部为ICMP,没有其他内容)
  • 并发性 - 您可能希望至少缓存/池化几秒钟的上/下状态,以便多个希望ping同一目标的客户端不会启动ping洪水攻击

5

我能想到的唯一方法是从外部服务器加载一个图片文件。当这个加载失败时,你会“知道”服务器没有响应(实际上你并不知道,因为服务器可能只是阻止了你)。

看一下这个示例代码,就可以理解我的意思:

 /*note that this is not an ICMP ping - but a simple HTTP request
    giving you an idea what you could do . In this simple implementation it has flaws
    as Piskvor correctly points out below */
    function ping(extServer){
     var ImageObject = new Image();
     ImageObject.src = "http://"+extServer+"/URL/to-a-known-image.jpg"; //e.g. logo -- mind the caching, maybe use a dynamic querystring
     if(ImageObject.height>0){
       alert("Ping worked!");
     } else {
       alert("Ping failed :(");
     }

}

9
那不是ping,那是一个HTTP请求(因此是TCP/IP)。而且,如果目标没有运行HTTP服务器,请求将需要很长时间才能超时;此外,加载是异步的 - 除非图像已经在缓存中,否则如果您在设置“src”后立即检查ImageObject.height,它将返回0;如果它已经被缓存,它将返回“Ping worked”,无论目标是否正常。http://en.wikipedia.org/wiki/Ping - Piskvor left the building
1
请不要把downvote当成个人攻击,我并没有downvote ;我只是觉得它并没有真正回答问题 - 尽管这确实是一种检查已知HTTP服务器是否在线的简单方法,但它并没有真正回答ping丢失或延迟的问题。我同意我的方法并不是从客户端计算机ping,那需要很多降低权限和许多安全漏洞(以及ActiveX)。 - Piskvor left the building
3
警告:上述内容将被缓存,请确保在URL的末尾添加一些唯一的内容。此外,仅一个IP/域名也可以用于图像的src属性:"http://" + ipOrHost + "?pingedat=" + new Date().getTime(); - fny

4
我受到了最新意见的启发,所以我写了这个快速代码片段。这是一种"HTTP ping",我认为可以与XMLHttpRequest调用一起使用,例如找出在某些情况下使用哪个最快的服务器或从用户的互联网连接速度收集一些粗略的统计数据。
这个小函数只是连接到一个不存在的URL上的HTTP服务器(预计返回404),然后测量服务器响应HTTP请求的时间,并对累积时间和迭代次数进行平均值。
每次调用时,请求的URL都会随机修改,因为我注意到(可能)某些透明代理或缓存机制在某些情况下会伪造结果,给出比ICMP更快的答案(有点奇怪)。
请注意使用适合真实HTTP服务器的FQDN!结果将显示在具有id“result”的body元素中,例如:
<div id="result"></div>

功能代码:

function http_ping(fqdn) {

var NB_ITERATIONS = 4; // number of loop iterations
var MAX_ITERATIONS = 5; // beware: the number of simultaneous XMLHttpRequest is limited by the browser!
var TIME_PERIOD = 1000; // 1000 ms between each ping
var i = 0;
var over_flag = 0;
var time_cumul = 0;
var REQUEST_TIMEOUT = 9000;
var TIMEOUT_ERROR = 0;

document.getElementById('result').innerHTML = "HTTP ping for " + fqdn + "</br>";

var ping_loop = setInterval(function() {


        // let's change non-existent URL each time to avoid possible side effect with web proxy-cache software on the line
        url = "http://" + fqdn + "/a30Fkezt_77" + Math.random().toString(36).substring(7);

        if (i < MAX_ITERATIONS) {

            var ping = new XMLHttpRequest();

            i++;
            ping.seq = i;
            over_flag++;

            ping.date1 = Date.now();

            ping.timeout = REQUEST_TIMEOUT; // it could happen that the request takes a very long time

            ping.onreadystatechange = function() { // the request has returned something, let's log it (starting after the first one)

                if (ping.readyState == 4 && TIMEOUT_ERROR == 0) {

                    over_flag--;

                    if (ping.seq > 1) {
                        delta_time = Date.now() - ping.date1;
                        time_cumul += delta_time;
                        document.getElementById('result').innerHTML += "</br>http_seq=" + (ping.seq-1) + " time=" + delta_time + " ms</br>";
                    }
                }
            }


            ping.ontimeout = function() {
                TIMEOUT_ERROR = 1;
            }

            ping.open("GET", url, true);
            ping.send();

        }

        if ((i > NB_ITERATIONS) && (over_flag < 1)) { // all requests are passed and have returned

            clearInterval(ping_loop);
            var avg_time = Math.round(time_cumul / (i - 1));
            document.getElementById('result').innerHTML += "</br> Average ping latency on " + (i-1) + " iterations: " + avg_time + "ms </br>";

        }

        if (TIMEOUT_ERROR == 1) { // timeout: data cannot be accurate

            clearInterval(ping_loop);
            document.getElementById('result').innerHTML += "<br/> THERE WAS A TIMEOUT ERROR <br/>";
            return;

        }

    }, TIME_PERIOD);
}

例如,使用以下方式启动:
fp = new http_ping("www.linux.com.au"); 

注意,我无法在此脚本的结果数字和相应服务器上的ICMP ping之间找到简单的关联,尽管HTTP响应时间似乎从ICMP响应时间粗略指数增长。这可以通过HTTP请求中传输的数据量来解释,该数据量可以根据Web服务器版本和配置而变化,显然,还包括服务器本身的速度和可能存在的其他原因。
这不是很好的代码,但我认为它可能有所帮助,并可能激发其他人的灵感。

3

在JS中,最接近ping的方法是使用AJAX,并检索readystates、状态和头信息。以下是一个示例:

url = "<whatever you want to ping>"
ping = new XMLHttpRequest();    
ping.onreadystatechange = function(){

    document.body.innerHTML += "</br>" + ping.readyState;

    if(ping.readyState == 4){
        if(ping.status == 200){
            result = ping.getAllResponseHeaders();
            document.body.innerHTML += "</br>" + result + "</br>";
        }
    }

}
ping.open("GET", url, true);    
ping.send();

当然,你也可以针对不同的http状态设置条件,并通过描述等方式使输出显示更加美观。这更像是一个HTTP URL状态检查器而不是ping,但本质相同。你也可以循环几次来让它更像ping :)

使用AJAX并检索ready states的IDE适合我。请问如何在此内容中添加else语句。例如,如果URL不可用,我想向用户打印一条消息。例如:document.getElementById("div").innerHTML = "Ping未成功!"; - Ibrahim İnce

2

由于我对搜索几个小时都没有找到的被大家认为“不可能”的东西感到厌倦,所以我想出了一个新的简单方法,使用基础JavaScript(没有其他任何东西)。

这是我的JSFiddle:https://jsfiddle.net/TheNolle/5qjpmrxg/74/

基本上,我创建了一个名为“start”的变量,给它一个时间戳,然后尝试将一个不是图片的源设置为我的网站(可以更改为任何网站)的不可见图像。因为它不是图像,所以会创建一个错误,我用它来执行代码的第二部分,在这个时候我创建了一个名为“end”的新变量,给它从这里获取的时间戳(与“start”不同)。之后,我只需做一个减法(从“end”中减去“start”),就能得到ping这个网站所花费的时间延迟。 在你选择后,你可以将其存储在一个值中,在你的网页上粘贴它,在控制台中粘贴它等等。

let pingSpan = document.getElementById('pingSpan');
// Remove all the way to ...
let run;

function start() {
  run = true;
  pingTest();
}

function stop() {
  run = false;
  setTimeout(() => {
    pingSpan.innerHTML = "Stopped !";
  }, 500);
}

// ... here

function pingTest() {
  if (run == true) { //Remove line
    let pinger = document.getElementById('pingTester');
    let start = new Date().getTime();
    pinger.setAttribute('src', 'https://www.google.com/');
    pinger.onerror = () => {
      let end = new Date().getTime();
      // Change to whatever you want it to be, I've made it so it displays on the page directly, do whatever you want but keep the "end - start + 'ms'"
      pingSpan.innerHTML = end - start + "ms";
    }
    setTimeout(() => {
      pingTest();
    }, 1000);
  } // Remove this line too
}
body {
  background: #1A1A1A;
  color: white
}

img {
  display: none
}
Ping:
<el id="pingSpan">Waiting</el>
<img id="pingTester">

<br> <br>

<button onclick="start()">
  Start Ping Test
</button>
<button onclick="stop()">
  Stop
</button>


0
function ping(url){
 new Image().src=url
}

上述代码会ping给定的URL。
通常用于计数器/分析工具。
它不会向客户端(JavaScript)返回失败的响应。


1
这将不会发送icmp数据包。 - mulllhausen
1
这将检查服务器是否响应请求,例如http请求。ping是完全不同的东西。 - Mike Causer

0

1
对这个答案进行负评并没有意义。问题是如何使用Javascript进行ping操作,而链接展示了如何有效地使用Javascript进行ping操作。不确定还有什么其他期望。感谢你的声望扣除,非常感激。哇。 - Jeffrey Tackett
是的,不应该被踩。我给了一个+1,所以应该能抵消那个踩的人(我猜的) :) - Arun Kumar
是的,不应该被踩。我给了一个+1,所以应该能抵消那个踩这个帖子的人(我猜):) - undefined

0

我建议使用“head”来仅请求头部信息。

xhr.open('head', 'asstes/imgPlain/pixel.txt' + cacheBuster(), true);

然后询问readyState 2 - HEADERS_RECEIVED, 表示已经调用了send()方法且头部和状态信息已经可用。

xhr.onreadystatechange = function() {
    if (xhr.readyState === 2) { ...

使用readyState 2是个不错的选择,因为它会更快地响应。此外,我建议请求一个小文件,比如一个空的.txt文件。 - undefined

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接