是否可以从Javascript ping服务器?


152

我正在制作一个Web应用程序,要求我检查远程服务器是否在线。当我从命令行运行它时,我的页面加载达到60s(对于8个条目,它将线性增加)。

我决定在用户​​端执行ping操作。这样,我可以加载页面并让他们在浏览内容时等待“服务器在线”数据。

如果有人对上述问题有答案,或者他们知道一种可以使我的页面快速加载的解决方案,我一定会很感激的。

Answers:


134

我发现有人通过非常巧妙地使用本机Image对象来完成此任务。

从它们的源头来看,这是主要功能(它与源头的其他部分有依赖关系,但您可以理解)。

function Pinger_ping(ip, callback) {

  if(!this.inUse) {

    this.inUse = true;
    this.callback = callback
    this.ip = ip;

    var _that = this;

    this.img = new Image();

    this.img.onload = function() {_that.good();};
    this.img.onerror = function() {_that.good();};

    this.start = new Date().getTime();
    this.img.src = "http://" + ip;
    this.timer = setTimeout(function() { _that.bad();}, 1500);

  }
}

这适用于我测试过的所有类型的服务器(Web服务器,FTP服务器和游戏服务器)。它还适用于端口。如果有人遇到失败的用例,请在评论中发布,我将更新答案。

更新:以前的链接已被删除。如果有人发现或实现了上述内容,请发表评论,我将其添加到答案中。

更新2:@trante足以提供jsFiddle。

http://jsfiddle.net/GSSCD/203/

更新3:@Jonathon使用实现创建了一个GitHub存储库。

https://github.com/jdfreder/pingjs

更新4:看来此实现不再可靠。人们还报告说Chrome不再支持所有功能,从而引发net::ERR_NAME_NOT_RESOLVED错误。如果有人可以验证替代解决方案,我将其作为公认的答案。


48
这就是我一直在使用的。但是,它确实有一个缺陷,那就是缓存了“图像”。最初对给定IP进行ping操作时,我得到304毫秒-但如果第二次对它进行ping操作而没有页面重新加载,则得到2毫秒。如果需要,可以通过"/?cachebreaker="+new Date().getTime();在img src的末尾附加a 来避免这种情况。
Meshaal 2012年

2
这对我不起作用,已知的错误主机名导致Ping请求找不到host ...。但是由于onerror是“好”的,所以这件事说了它的回应
Maslow 2013年

5
更多测试表明,这是完全不可靠的。
Leo 2015年

2
@Jonathon创建的Ping API将成功ping所有内容。不存在的站点和随机字符。
IE5Master

2
实际上,Ping API总是失败,并显示onerror。但是,如果目标URL表示图像,则会触发onload,这真棒!绕过CORS检查。
Martin Vysny

20

Ping是ICMP,但是如果远程服务器上有任何开放的TCP端口,则可以这样实现:

function ping(host, port, pong) {

  var started = new Date().getTime();

  var http = new XMLHttpRequest();

  http.open("GET", "http://" + host + ":" + port, /*async*/true);
  http.onreadystatechange = function() {
    if (http.readyState == 4) {
      var ended = new Date().getTime();

      var milliseconds = ended - started;

      if (pong != null) {
        pong(milliseconds);
      }
    }
  };
  try {
    http.send(null);
  } catch(exception) {
    // this is expected
  }

}


我喜欢这个棘手的解决方案。必须提供pong函数而不是返回数字对我来说有点奇怪,但可行。
尼克

@armen:您必须提供一个函数作为ping()的第三个参数,该参数的值在函数内称为pong。
finitud 2013年

2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); }).....示例通话
jave.web 2015年

@Nick:这是异步内容,因此在方法返回时,onreadystatechange尚未触发。这意味着您需要在状态更改时进行回调。
敬畏

无论我为主机选择什么,都会调用pong()。ping(test.zzzzzzzzz,“ 77”,function(m){console.log(“花费了” + m +“毫秒。”);})打印“花费了67毫秒。” ping(stackoverflow.com,“ 80”,function(m){console.log(“花费了“ + m +”毫秒。”);})给出了CORS错误:developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Errors /… 如果远程计算机联机,我看不到如何使用此代码进行检查。
Tux

18

您可以尝试以下方法:

ping.html放在有或没有任何内容的服务器上,在javascript上执行以下操作:

<script>
    function ping(){
       $.ajax({
          url: 'ping.html',
          success: function(result){
             alert('reply');
          },     
          error: function(result){
              alert('timeout/error');
          }
       });
    }
</script>

1
我要ping的服务器不是我自己的,因此我没有该选项。不过谢谢
Chuck Callebs

9
@dlchambers不是由于CORS引起的,而是由于跨域策略。CORS允许服务器指定来源,并且浏览器必须支持它。因此它更像是跨域问题。
罗伊·纳米尔

HEAD类型请求也不会由于CORS而起作用。使用Chromium 55进行了测试。例如,对于net :: CONNECTION_REFUSED,使用http代码0接收到相同的错误。
Martin Vysny

不幸的是,这是跨浏览器。
加百利

14

您无法在javascript中直接“ ping”。可能还有其他几种方法:

  • 阿贾克斯
  • isReachable中使用Java Applet
  • 编写可ping的服务器端脚本,并使用AJAX与您的服务器端脚本进行通信
  • 您也许还可以ping通Flash(动作脚本)

1
Java的isReachable是非常不可靠的...。但是到了2018年,Java Applet还是过时了。
dreua

8

您无法在浏览器Javascript中执行常规ping操作,但是可以通过例如从远程服务器加载图像来确定远程服务器是否处于活动状态。如果加载失败->服务器关闭。

您甚至可以使用onload-event计算加载时间。这是一个如何使用onload事件的示例


4
不幸的是,我正在ping的服务器不是Web服务器。他们是游戏服务器。
Chuck Callebs

1
然后,您必须在服务器端执行ping操作-否则您可以考虑使用一些轻量级的http服务器。
Epeli

您知道汇总ping的方法吗?那是我的主要减速,等待一个请求完成,然后再开始另一个。
Chuck Callebs

您需要同时ping服务器。您可以通过选择,线程或进程来实现。对于真正的核心解决方案,您可以使用Eventmachine。
Epeli

1
您可能会考虑利用命令行ping命令。这是工业实力。或者,有各种各样的免费/开源应用程序,可以使用各种类型的心跳检查来监视主机是否正在运行。
Tin Man

7

投身websocket解决方案...

function ping(ip, isUp, isDown) {
  var ws = new WebSocket("ws://" + ip);
  ws.onerror = function(e){
    isUp();
    ws = null;
  };
  setTimeout(function() { 
    if(ws != null) {
      ws.close();
      ws = null;
      isDown();
    }
  },2000);
}

不应该isUp();调用在onopen事件处理程序?:)
jave.web

1
它使用websocket协议,但假定实际上没有Websocket服务器在等待连接。这仅用于ping“任何旧IP”。
安东尼·伍兹

但是,如何检测是否仅不支持WebSocket或确实存在某些错误?:)
jave.web 2015年

如果认为您很不幸无法ping通可以在端口80上接受websocket连接的IP ,那么可以,您应该添加isUp();该回调。或通过添加一个明显非websocket-y的端口来缓解这种情况。
安东尼·伍兹

我之所以投票赞成这是因为我来这里寻求解决方案是,当我的Websocket服务器重新启动时会发生什么,而这个答案表明我可以在套接字的错误处理程序中设置setTimeout并尝试重新连接(繁忙等待)。可能不是最佳做法,但可以解决我的问题。:)
mynameisnafe

6

为了保持快速的请求,请缓存ping的服务器端结果,并每隔几分钟(或精确到所需的时间)更新ping文件或数据库。您可以使用cron使用您的8个ping命令运行shell命令并将输出写入文件中,网络服务器会将这个文件包含在您的视图中。


我认为这是最可靠的方法,可能会获得最佳结果。但是,由于它仍需要在服务器上进行一些工作,因此我认为这不是明智的方法。
Chetabahana

5

如果您要查看的是服务器是否“存在”,则可以使用以下命令:

function isValidURL(url) {
    var encodedURL = encodeURIComponent(url);
    var isValid = false;

    $.ajax({
      url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
      type: "get",
      async: false,
      dataType: "json",
      success: function(data) {
        isValid = data.query.results != null;
      },
      error: function(){
        isValid = false;
      }
    });

    return isValid;
}

这将返回一个真/假指示服务器是否存在。

如果您需要响应时间,则可以进行一些修改:

function ping(url) {
    var encodedURL = encodeURIComponent(url);
    var startDate = new Date();
    var endDate = null;
    $.ajax({
      url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
      type: "get",
      async: false,
      dataType: "json",
      success: function(data) {
        if (data.query.results != null) {
            endDate = new Date();
        } else {
            endDate = null;
        }
      },
      error: function(){
        endDate = null;
      }
    });

    if (endDate == null) {
        throw "Not responsive...";
    }

    return endDate.getTime() - startDate.getTime();
}

用法很简单:

var isValid = isValidURL("http://example.com");
alert(isValid ? "Valid URL!!!" : "Damn...");

要么:

var responseInMillis = ping("example.com");
alert(responseInMillis);

尽管此链接可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。如果链接的页面发生更改,仅链接的答案可能会失效。
vonbrand 2014年

1
这是一个很好的解决方案,但是不幸的是,雅虎域查询服务似乎提供了可变的结果。例如,如果您尝试以下URL,则begin-download .com beginfreedownload .com会以未注册的形式返回,但是如果您访问这些URL,则它们显然已注册。你知道这是怎么回事吗?(在这些示例中,我在域名中添加了一个空格,只是为了避免散发出Google果汁。在我的测试中,我在其中没有空格)
user280109 2016年

您正在向Yahoo!发送请求。API,如果您从计算机发出请求,则ping甚至不会相同。这没有道理
Andre Figueiredo

这会导致No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin成功回调从未被调用
vladkras

4

标准ping的问题在于它们是ICMP,出于安全和流量方面的原因很多地方不允许通过。那可以解释失败的原因。

1.9之前的Ruby具有基于TCP的ping.rb,它将与Ruby 1.9+一起运行。您所要做的就是将其从1.8.7安装复制到其他地方。我刚刚确认可以通过对我的家用路由器执行ping操作来运行。


4

这里有很多疯狂的答案,尤其是关于CORS的答案-

您可以执行http HEAD请求(如GET但没有有效负载)。参见https://ochronus.com/http-head-request-good-uses/

它不需要进行预检,这是由于规范的旧版本引起的,请参阅 为什么跨域HEAD请求需要进行预检?

因此,您可以使用上面的答案,该答案使用的是jQuery库(没有说出来),但是

type: 'HEAD'

->

<script>
    function ping(){
       $.ajax({
          url: 'ping.html',
          type: 'HEAD',
          success: function(result){
             alert('reply');
          },     
          error: function(result){
              alert('timeout/error');
          }
       });
    }
</script>

当然,您也可以使用vanilla js或dojo或其他任何方法。


1
发送HEAD请求仍然失败,并且“ XMLHttpRequest无法加载IP。所请求的资源上没有'Access-Control-Allow-Origin'标头。因此,不允许对源'ip2'的访问。” 因此被CORS封锁。您将获得http状态为0的成功,因此您将无法与net :: ERR_CONNECTION_REFUSED区别开来
Martin Vysny,2017年


-1
let webSite = 'https://google.com/' 
https.get(webSite, function (res) {
    // If you get here, you have a response.
    // If you want, you can check the status code here to verify that it's `200` or some other `2xx`.
    console.log(webSite + ' ' + res.statusCode)
}).on('error', function(e) {
    // Here, an error occurred.  Check `e` for the error.
    console.log(e.code)
});;

如果您使用节点运行此命令,只要google尚未关闭,它将控制台日志200。


不,不是... 1)您缺少需求,2)返回301永久移动:D
Michal MikyJankovský19年

-1
const ping = (url, timeout = 6000) => {
  return new Promise((reslove, reject) => {
    const urlRule = new RegExp('(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]');
    if (!urlRule.test(url)) reject('invalid url');
    try {
      fetch(url)
        .then(() => reslove(true))
        .catch(() => reslove(false));
      setTimeout(() => {
        reslove(false);
      }, timeout);
    } catch (e) {
      reject(e);
    }
  });
};

像这样使用:

ping('https://stackoverflow.com/')
  .then(res=>console.log(res))
  .catch(e=>console.log(e))

-4

您可以使用以下方法从javaScript运行DOS ping.exe命令:

function ping(ip)
{
    var input = "";
    var WshShell = new ActiveXObject("WScript.Shell");
    var oExec = WshShell.Exec("c:/windows/system32/ping.exe " + ip);

    while (!oExec.StdOut.AtEndOfStream)
    {
            input += oExec.StdOut.ReadLine() + "<br />";
    }
    return input;
}

这是所要的,还是我缺少了什么?


4
不幸的是,这仅适用于IE,并且仅适用于Windows Server。更好的选择是使用AJAX运行服务器端脚本。
Andrew Grothe

有没有搞错?Active X对象可以在用户文件系统中执行(在Win服务器上的IE中)吗?我没有使用ActiveX,但没有想到...
Julix

-6

只需更换

file_get_contents

$ip = $_SERVER['xxx.xxx.xxx.xxx'];
exec("ping -n 4 $ip 2>&1", $output, $retval);
if ($retval != 0) { 
  echo "no!"; 
} 
else{ 
  echo "yes!"; 
}

1
您应该编辑以前的答案,而不是添加新的“部分” 答案
Artemix

-8

这可能比这简单得多。如果要加载页面,然后检查某些外部页面的可用性或内容以触发其他网页活动,则可以仅使用javascript和php这样来完成。

yourpage.php

<?php
if (isset($_GET['urlget'])){
  if ($_GET['urlget']!=''){
    $foreignpage= file_get_contents('http://www.foreignpage.html');
    // you could also use curl for more fancy internet queries or if http wrappers aren't active in your php.ini
    // parse $foreignpage for data that indicates your page should proceed
    echo $foreignpage; // or a portion of it as you parsed
    exit();  // this is very important  otherwise you'll get the contents of your own page returned back to you on each call
  }
}
?>

<html>
  mypage html content
  ...

<script>
var stopmelater= setInterval("getforeignurl('?urlget=doesntmatter')", 2000);

function getforeignurl(url){
  var handle= browserspec();
  handle.open('GET', url, false);
  handle.send();
  var returnedPageContents= handle.responseText;
  // parse page contents for what your looking and trigger javascript events accordingly.
  // use handle.open('GET', url, true) to allow javascript to continue executing. must provide a callback function to accept the page contents with handle.onreadystatechange()
}
function browserspec(){
  if (window.XMLHttpRequest){
    return new XMLHttpRequest();
  }else{
    return new ActiveXObject("Microsoft.XMLHTTP");
  }
}

</script>

那应该做。

触发的javascript应该包括clearInterval(stopmelater)

让我知道这是否适合您

杰瑞


2
如前所述,这些不是我要查询的Web服务器。这些是游戏服务器。他们不会响应HTTP请求。:(
Chuck Callebs 2012年

花花公子,只需将file_get_contents替换为
Jerry Wickey

$ ip = $ _SERVER ['127.0.0.1']; exec(“ ping -n 4 $ ip 2>&1”,$ output,$ retval); 如果($ retval!= 0){echo“ no!”; } else {回声“是!”;}
Jerry Wickey 2012年

4
这不是PHP问题。这是一个JavaScript问题。我不使用PHP。
Chuck Callebs 2012年

1
请不要在帖子中使用签名或标语,否则它们将被删除。有关详细信息,请参见常见问题解答
Artemix

-13

您可以尝试在网页中使用PHP ...类似这样的内容:

<html><body>
<form method="post" name="pingform" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<h1>Host to ping:</h1>
<input type="text" name="tgt_host" value='<?php echo $_POST['tgt_host']; ?>'><br>
<input type="submit" name="submit" value="Submit" >
</form></body>
</html>
<?php

$tgt_host = $_POST['tgt_host'];
$output = shell_exec('ping -c 10 '. $tgt_host.');

echo "<html><body style=\"background-color:#0080c0\">
<script type=\"text/javascript\" language=\"javascript\">alert(\"Ping Results: " . $output . ".\");</script>
</body></html>";

?>

这没有经过测试,所以可能会有错别字等。但是我相信它会起作用。也可以改善...


5
根据OP的标签,这实际上是Ruby on Rails的问题,因此使用PHP并不是一个好的解决方案。
Tin Man

1
不要在这里开始争论,但是这个论坛无济于事吗?
克里斯,2010年

5
@Chris是的,但是您通过提供PHP代码给在他的应用程序中使用Ruby和JS的OP提供了什么样的帮助?
biphobe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.