Ist es möglich, einen Server über Javascript zu pingen?

152

Ich erstelle eine Web-App, bei der ich überprüfen muss, ob Remoteserver online sind oder nicht. Wenn ich es über die Befehlszeile ausführe, wird meine Seite auf volle 60 Sekunden geladen (bei 8 Einträgen wird sie linear mit mehr skaliert).

Ich beschloss, den Weg des Pingens am Ende des Benutzers zu beschreiten. Auf diese Weise kann ich die Seite laden und sie beim Durchsuchen meiner Inhalte auf die Daten "Server ist online" warten lassen.

Wenn jemand die Antwort auf die obige Frage hat oder eine Lösung kennt, um das Laden meiner Seite schnell zu halten, würde ich es auf jeden Fall begrüßen.

Chuck Callebs
quelle

Antworten:

134

Ich habe jemanden gefunden, der dies mit einer sehr geschickten Verwendung des nativen ImageObjekts erreicht.

Von ihrer Quelle aus ist dies die Hauptfunktion (sie hat Abhängigkeiten von anderen Teilen der Quelle, aber Sie bekommen die Idee).

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

  }
}

Dies funktioniert auf allen Arten von Servern, die ich getestet habe (Webserver, FTP-Server und Spieleserver). Es funktioniert auch mit Ports. Wenn jemand auf einen Anwendungsfall stößt, der fehlschlägt, posten Sie bitte in den Kommentaren und ich werde meine Antwort aktualisieren.

Update : Vorheriger Link wurde entfernt. Wenn jemand das oben Gesagte findet oder implementiert, kommentieren Sie es bitte und ich werde es der Antwort hinzufügen.

Update 2 : @trante war nett genug, um eine jsFiddle bereitzustellen.

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

Update 3 : @Jonathon hat mit der Implementierung ein GitHub-Repo erstellt.

https://github.com/jdfreder/pingjs

Update 4 : Es sieht so aus, als ob diese Implementierung nicht mehr zuverlässig ist. Die Leute berichten auch, dass Chrome nicht mehr alles unterstützt und einen net::ERR_NAME_NOT_RESOLVEDFehler auslöst. Wenn jemand eine alternative Lösung überprüfen kann, werde ich dies als akzeptierte Antwort angeben.

Chuck Callebs
quelle
48
Das habe ich benutzt. Es hat jedoch einen Fehler, nämlich dass das "Bild" zwischengespeichert wird. Wenn ich anfänglich eine bestimmte IP anpinge, erhalte ich 304 ms. Wenn ich sie jedoch ein zweites Mal ohne erneutes Laden der Seite anpinge, erhalte ich stattdessen 2 ms. Dies könnte vermieden werden, indem "/?cachebreaker="+new Date().getTime();bei Bedarf ein an das Ende des img src angehängt wird.
Meshaal
2
Dies funktioniert bei mir nicht. Ein bekannter falscher Hostname führt dazu, dass die Ping-Anfrage den Host nicht finden konnte .... aber da onerror 'gut' ist, sagt dieses Ding, dass es geantwortet hat
Maslow
5
Weitere Tests ergaben, dass dies völlig unzuverlässig ist.
Leo
2
Die von @Jonathon erstellte Ping-API pingt erfolgreich alles. Nicht vorhandene Websites und zufällige Zeichen.
IE5Master
2
Die Ping-API schlägt tatsächlich immer mit einem Fehler fehl. JEDOCH, wenn die Ziel-URL ein Bild kennzeichnet, wird eine Onload ausgelöst, was fantastisch ist! Umgeht CORS-Prüfungen.
Martin Vysny
20

Ping ist ICMP, aber wenn auf dem Remote-Server ein offener TCP-Port vorhanden ist, kann dies folgendermaßen erreicht werden:

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
  }

}

Nils Holgersson
quelle
Ich mag diese knifflige Lösung. Eine Funktion für Pong bereitstellen zu müssen, anstatt eine Nummer zurückzugeben, ist für mich etwas seltsam, aber praktikabel.
Nick
@armen: Sie müssen eine Funktion als drittes Argument für ping () angeben. Der Wert dieses Arguments wird innerhalb der Funktion als pong bezeichnet.
Endlichkeit
2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); })..... Beispiel Anruf
jave.web
@Nick: Dies ist asynchrones Material. Zum Zeitpunkt der Rückkehr der Methode wurde das onreadystatechangenoch nicht ausgelöst. Dies bedeutet, dass Sie einen Rückruf benötigen, um den Status zu ändern.
Ehrfurcht
Was auch immer ich für Host wähle, pong () heißt. ping ( test.zzzzzzzzz, "77", function (m) {console.log ("Es hat" + m + "Millisekunden gedauert.");}) druckt "Es hat 67 Millisekunden gedauert." ping ( stackoverflow.com, "80", function (m) {console.log ("Es hat" + m + "Millisekunden gedauert.");}) gibt einen CORS-Fehler aus: developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Errors /… Ich sehe nicht, wie ich mit diesem Code überprüfen kann, ob ein Remotecomputer online ist.
Tux
18

Sie können dies versuchen:

setzen ping.html auf dem Server mit oder ohne Inhalt, auf dem Javascript tut selber wie unten:

<script>
    function ping(){
       $.ajax({
          url: 'ping.html',
          success: function(result){
             alert('reply');
          },     
          error: function(result){
              alert('timeout/error');
          }
       });
    }
</script>
jerjer
quelle
1
Die Server, die ich anpinge, sind nicht meine eigenen, daher habe ich diese Option nicht. Trotzdem danke.
Chuck Callebs
9
@dlchambers Nicht wegen CORS, sondern wegen domänenübergreifender Poilicy. Mit CORS kann ein Server die Ursprünge angeben und es muss vom Browser unterstützt werden. Es ist also eher ein domänenübergreifendes Problem.
Royi Namir
Die Anforderungen vom Typ HEAD funktionieren auch aufgrund von CORS nicht. Getestet mit Chromium 55. Empfangen des gleichen Fehlers mit http-Code 0 wie beispielsweise im Fall von net :: CONNECTION_REFUSED.
Martin Vysny
Dies ist eher browserübergreifend.
Gabriel
14

Sie können nicht direkt in Javascript "pingen". Es kann einige andere Möglichkeiten geben:

  • Ajax
  • Verwenden eines Java-Applets mit isReachable
  • Schreiben eines serverseitigen Skripts, das pingt, und Verwenden von AJAX zur Kommunikation mit Ihrem serverseitigen Skript
  • Möglicherweise können Sie auch in Flash (Actionscript) pingen.
Eugene
quelle
1
Javas isReachable ist ziemlich unzuverlässig ... Aber es ist 2018 und Java Applets sind sowieso veraltet.
Dreua
8

Sie können im Browser-Javascript kein reguläres Ping durchführen, aber Sie können herausfinden, ob der Remote-Server aktiv ist, indem Sie beispielsweise ein Image vom Remote-Server laden. Wenn das Laden fehlschlägt -> Server heruntergefahren.

Sie können die Ladezeit sogar mithilfe des Onload-Ereignisses berechnen. Hier ist ein Beispiel für die Verwendung des Onload-Ereignisses.

Epeli
quelle
4
Das Unglückliche daran ist, dass die Server, die ich anpinge, keine Webserver sind. Sie sind Spieleserver.
Chuck Callebs
1
Dann müssen Sie das Ping auf der Serverseite durchführen - oder Sie könnten einen leichten http-Server in Betracht ziehen.
Epeli
Kennen Sie eine Möglichkeit, aggregierte Pings zu erstellen? Das ist meine Hauptverlangsamung und ich warte darauf, dass eine Anfrage beendet wird, bevor die andere beginnt.
Chuck Callebs
Sie müssen die Server gleichzeitig anpingen. Sie können dies mit select, threads oder Prozessen erreichen. Für eine wirklich Hardcore-Lösung können Sie Eventmachine verwenden.
Epeli
1
Möglicherweise möchten Sie den pingBefehlszeilenbefehl nutzen. Es ist industrielle Stärke. Oder es gibt alle Arten von kostenlosen / Open-Source-Apps, mit denen mithilfe verschiedener Arten von Heartbeat-Checks überwacht werden kann, ob ein Host ausgeführt wird.
der Blechmann
7

Mit einer Websocket-Lösung einsteigen ...

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);
}
Antony Woods
quelle
Sollte der isUp();Anruf nicht im onopenEvent-Handler sein? :)
jave.web
1
Es verwendet das Websocket-Protokoll, geht jedoch davon aus, dass tatsächlich kein Websocket-Server auf eine Verbindung wartet. Dies ist nur zum Pingen von "jeder alten IP".
Antony Woods
Aber wie können Sie feststellen, ob WebSocket einfach nicht unterstützt wird oder ob tatsächlich ein Fehler aufgetreten ist? :)
jave.web
Wenn Sie der Meinung sind, dass Sie das Pech haben, eine IP- Adresse zu pingen , die eine Websocket-Verbindung an Port 80 akzeptieren könnte , sollten Sie diesen Rückruf ebenfalls ergänzen isUp();. Oder verringern Sie dies, indem Sie einen eindeutig nicht Websocket-y-Port hinzufügen.
Antony Woods
Ich habe dafür gestimmt, weil ich hierher gekommen bin, um nach einer Lösung für das zu suchen, was passiert, wenn mein Websocket-Server neu gestartet wird. Diese Antwort hat mir gezeigt, dass ich Timeout in der Fehlerbehandlungsroutine des Sockets einstellen und versuchen kann, die Verbindung wiederherzustellen (Wartezeit beschäftigt). Wahrscheinlich nicht die beste Vorgehensweise, löst aber mein Problem. :)
mynameisnafe
6

Um Ihre Anforderungen schnell zu halten, speichern Sie die serverseitigen Ergebnisse des Pings zwischen und aktualisieren Sie die Ping-Datei oder -Datenbank alle paar Minuten (oder wie genau Sie dies wünschen). Sie können cron verwenden, um einen Shell-Befehl mit Ihren 8 Pings auszuführen und die Ausgabe in eine Datei zu schreiben. Der Webserver wird diese Datei in Ihre Ansicht aufnehmen.

user456733
quelle
Ich denke, dies ist der zuverlässigste Weg mit dem bestmöglichen Ergebnis. Da es jedoch noch einige Arbeiten auf dem Server erfordert, würde ich sagen, dass dies kein kluger Weg ist.
Chetabahana
5

Wenn Sie versuchen zu sehen, ob der Server "existiert", können Sie Folgendes verwenden:

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;
}

Dies gibt eine wahr / falsch-Angabe zurück, ob der Server vorhanden ist.

Wenn Sie eine Antwortzeit wünschen, reicht eine geringfügige Änderung aus:

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

Die Verwendung ist dann trivial:

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

Oder:

var responseInMillis = ping("example.com");
alert(responseInMillis);
Ohad
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
vonbrand
1
Dies ist eine großartige Lösung, aber leider scheint der Yahoo Domain-Abfragedienst variable Ergebnisse zu liefern. Wenn Sie beispielsweise die folgenden URLs ausprobieren, beginnen Sie mit dem Herunterladen .com beginfreedownload .com. Sie werden als nicht registriert zurückgegeben. Wenn Sie jedoch zu diesen URLs wechseln, sind sie eindeutig registriert. Hast du eine Idee, was hier los ist? (Ich habe den Domain-Namen in diesen Beispielen ein Leerzeichen hinzugefügt, um zu vermeiden, dass Google Juice ausgegeben wird. In meinem Test hatte ich kein Leerzeichen in ihnen)
user280109
Sie senden eine Anfrage an Yahoo! API, Ping ist nicht einmal dasselbe, wenn Sie eine Anfrage von Ihrem Computer aus ausführen. Das macht keinen Sinn
Andre Figueiredo
Dies verursacht No 'Access-Control-Allow-Origin' header is present on the requested resource. Originund Erfolg Rückruf wird nie genannt
vladkras
4

Das Problem mit Standard-Pings ist, dass es sich um ICMP handelt, die an vielen Stellen aus Sicherheits- und Verkehrsgründen nicht durchgelassen werden . Das könnte den Fehler erklären.

Ruby vor 1.9 hatte eine TCP-basierte ping.rbVersion, die mit Ruby 1.9+ ausgeführt werden kann. Sie müssen es lediglich von der 1.8.7-Installation an einen anderen Ort kopieren. Ich habe gerade bestätigt, dass es ausgeführt wird, indem ich meinen Heimrouter anpinge.

der Blechmann
quelle
4

Hier gibt es viele verrückte Antworten und besonders zu CORS -

Sie können eine http HEAD-Anforderung ausführen (wie GET, jedoch ohne Nutzlast). Siehe https://ochronus.com/http-head-request-good-uses/

Es ist KEINE Preflight-Prüfung erforderlich. Die Verwirrung ist auf eine alte Version der Spezifikation zurückzuführen. Siehe Warum benötigt eine HEAD-Anforderung mit Ursprung im Ursprung eine Preflight-Prüfung?

Sie könnten also die obige Antwort verwenden, die die jQuery-Bibliothek verwendet (hat es nicht gesagt), aber mit

type: 'HEAD'

--->

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

Natürlich können Sie auch Vanille js oder Dojo oder was auch immer verwenden ...

Sebilasse
quelle
1
Das Senden der HEAD-Anforderung schlägt weiterhin fehl mit "XMLHttpRequest kann keine IP laden. In der angeforderten Ressource ist kein Header 'Access-Control-Allow-Origin' vorhanden. Origin 'ip2' ist daher kein Zugriff gestattet." Also von CORS blockiert. Sie erhalten Erfolg mit http Status 0, und Sie können dies daher nicht von net :: ERR_CONNECTION_REFUSED zum Beispiel unterscheiden
Martin Vysny
0

Ich weiß nicht, welche Version von Ruby Sie ausführen, aber haben Sie versucht, Ping für Ruby anstelle von Javascript zu implementieren? http://raa.ruby-lang.org/project/net-ping/

wajiw
quelle
Ja, das habe ich versucht, aber die Pings sind immer falsch zurückgekommen, unabhängig vom Webserver. Ich habe es geändert, um nur die ping server.comSyntax zu verwenden.
Chuck Callebs
-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)
});;

Wenn Sie dies mit Node ausführen, wird das Protokoll 200 konsolidiert, solange Google nicht inaktiv ist.

LifterCoder
quelle
nein, es ist nicht ... 1) Sie werden vermisst benötigen, 2) es kehrt zurück 301 Permanent verschoben: D
Michal Miky Jankovský
-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);
    }
  });
};

Verwendung wie folgt:

ping('https://stackoverflow.com/')
  .then(res=>console.log(res))
  .catch(e=>console.log(e))
王玉 略
quelle
-4

Sie können den DOS-Befehl ping.exe über JavaScript wie folgt ausführen:

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;
}

Wurde danach gefragt oder fehlt mir etwas?

Garryg
quelle
4
Dies funktioniert leider nur im IE und nur auf einem Windows Server. Eine bessere Option wäre die Verwendung von AJAX zum Ausführen eines serverseitigen Skripts.
Andrew Grothe
Was zum Teufel? Active X-Objekte können im Dateisystem des Benutzers ausgeführt werden (im IE auf dem Win-Server)? Ich hatte nicht mit ActiveX gearbeitet, aber ich habe mir das nicht vorgestellt ...
Julix
-6

einfach ersetzen

file_get_contents

mit

$ip = $_SERVER['xxx.xxx.xxx.xxx'];
exec("ping -n 4 $ip 2>&1", $output, $retval);
if ($retval != 0) { 
  echo "no!"; 
} 
else{ 
  echo "yes!"; 
}
Jerry Wickey
quelle
1
Sie sollten Ihre vorherige Antwort bearbeiten , anstatt eine neue "teilweise" Antwort hinzuzufügen.
Artemix
-8

Es könnte viel einfacher sein als das alles. Wenn Sie möchten, dass Ihre Seite geladen wird, überprüfen Sie die Verfügbarkeit oder den Inhalt einer fremden Seite, um andere Webseitenaktivitäten auszulösen. Sie können dies nur mit Javascript und PHP wie diesem tun.

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>

Das sollte es tun.

Das ausgelöste Javascript sollte clearInterval (stopmelater) enthalten.

Lassen Sie mich wissen, ob das für Sie funktioniert

Jerry

Jerry Wickey
quelle
2
Wie ich bereits sagte, sind dies keine Webserver, die ich anpinge. Dies sind Spieleserver. Sie antworten nicht auf HTTP-Anfragen. :(
Chuck Callebs
Alter, ersetze einfach file_get_contents durch
Jerry Wickey
$ ip = $ _SERVER ['127.0.0.1']; exec ("ping -n 4 $ ip 2> & 1", $ output, $ retval); if ($ retval! = 0) {echo "no!"; } else {echo "yes!"; }
Jerry Wickey
4
Dies ist keine PHP-Frage. Dies ist eine JavaScript-Frage. Ich benutze kein PHP.
Chuck Callebs
1
Bitte verwenden Sie keine Signaturen oder Slogans in Ihren Posts, da diese sonst entfernt werden. Siehe FAQ für Details.
Artemix
-13

Sie könnten versuchen, PHP auf Ihrer Webseite zu verwenden ... ungefähr so:

<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>";

?>

Dies ist nicht getestet, so dass es Tippfehler usw. geben kann ... aber ich bin zuversichtlich, dass es funktionieren würde. Könnte auch verbessert werden ...

Chris
quelle
5
Laut den Tags des OP handelt es sich tatsächlich um eine Ruby on Rails-Frage, daher ist die Verwendung von PHP keine gute Lösung.
der Blechmann
1
Hier kein Argument zu beginnen, aber ist der Sinn dieses Forums nicht zu helfen?
Chris
5
@ Chris Es ist, aber welche Art von Hilfe haben Sie OP gegeben, der Ruby und JS in seiner Anwendung verwendet, indem er PHP-Code bereitstellt?
Biphobe