È possibile eseguire il ping di un server da Javascript?


152

Sto realizzando un'app Web che richiede di verificare se i server remoti sono online o meno. Quando lo eseguo dalla riga di comando, il mio caricamento della pagina arriva fino a un massimo di 60 anni (per 8 voci, si ridimensionerà linearmente con più).

Ho deciso di seguire il percorso del ping sul lato dell'utente. In questo modo, posso caricare la pagina e farli attendere i dati "il server è online" mentre sfoglio i miei contenuti.

Se qualcuno ha la risposta alla domanda di cui sopra, o se conoscono una soluzione per mantenere il caricamento veloce della mia pagina, lo apprezzerei sicuramente.

Risposte:


134

Ho trovato qualcuno che realizza questo con un uso molto intelligente Imagedell'oggetto nativo .

Dalla loro fonte, questa è la funzione principale (ha dipendenze da altre parti della fonte ma hai l'idea).

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

  }
}

Funziona su tutti i tipi di server che ho testato (server Web, server ftp e server di gioco). Funziona anche con le porte. Se qualcuno incontra un caso d'uso che non riesce, si prega di pubblicare i commenti e aggiornerò la mia risposta.

Aggiornamento : il link precedente è stato rimosso. Se qualcuno trova o implementa quanto sopra, commenta e lo aggiungerò nella risposta.

Aggiornamento 2 : @trante è stato abbastanza carino da fornire un jsFiddle.

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

Aggiornamento 3 : @Jonathon ha creato un repository GitHub con l'implementazione.

https://github.com/jdfreder/pingjs

Aggiornamento 4 : sembra che questa implementazione non sia più affidabile. Le persone segnalano inoltre che Chrome non supporta più tutto, generando un net::ERR_NAME_NOT_RESOLVEDerrore. Se qualcuno può verificare una soluzione alternativa, la inserirò come risposta accettata.


48
Questo è quello che ho usato. Ha un difetto, tuttavia, e cioè che "l'immagine" è memorizzata nella cache. Quando eseguo inizialmente il ping di un determinato IP, ottengo 304 ms, ma se eseguo il ping una seconda volta senza ricaricare la pagina, ottengo invece 2 ms. Ciò potrebbe essere evitato aggiungendo "/?cachebreaker="+new Date().getTime();a alla fine di img src, se necessario.
Meshaal,

2
questo non funziona per me, un nome host non valido noto nella richiesta di ping non è riuscito a trovare l'host .... ma poiché onerror è "buono" questa cosa dice che ha risposto
Maslow

5
Altri test hanno rivelato che questo è totalmente inaffidabile.
Leo,

2
L'API Ping creata da @Jonathon eseguirà correttamente il ping di tutto. Siti che non esistono e caratteri casuali.
IE5 Master

2
L'API Ping in realtà fallisce sempre con onerror. TUTTAVIA se l'URL di destinazione indica un'immagine, si attiva al caricamento, il che è fantastico! Ignora i controlli CORS.
Martin Vysny,

20

Il ping è ICMP, ma se sul server remoto è presente una porta TCP aperta, è possibile ottenere così:

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
  }

}


Mi piace questa soluzione complicata. Dover fornire una funzione per pong invece di restituire un numero è un po 'strano per me ma fattibile.
Nick,

@armen: devi fornire una funzione come terzo argomento a ping (), il valore di questo argomento è chiamato pong all'interno della funzione.
finitud

2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); })..... esempio chiamata
jave.web

@Nick: questa è roba asincrona, quindi al momento in cui il metodo ritorna onreadystatechangenon è ancora stato attivato . Ciò significa che è necessario un callback per rispondere quando cambia lo stato.
timore il

Qualunque cosa scelga per l'host, si chiama pong (). ping ( test.zzzzzzzzz, "77", function (m) {console.log ("Ci sono voluti" + m + "millisecondi.");}) stampa "Ci sono voluti 67 millisecondi." ping ( stackoverflow.com, "80", function (m) {console.log ("Ci sono voluti" + m + "milisecondi.");}) restituisce un errore CORS: developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Errori / ... Non vedo come posso verificare con questo codice se un computer remoto è online.
Tux

18

puoi provare questo:

metti ping.html sul server con o senza alcun contenuto, su javascript fai come di seguito:

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

1
I server che sto eseguendo il ping non sono i miei, quindi non ho questa opzione. Grazie comunque.
Chuck Callebs,

9
@dlchambers Non è dovuto a CORS ma A DOVUTA poetica tra domini. CORS consente a un server di specificare le origini e inoltre deve essere supportato dal browser. quindi è più simile a un problema tra domini.
Royi Namir,

Le richieste di tipo HEAD non funzioneranno neanche a causa di CORS. Testato con Chromium 55. Ricezione dello stesso errore con il codice http 0 come nel caso di net :: CONNECTION_REFUSED per esempio.
Martin Vysny,

Questo è più miracoloso per browser.
Gabriel,

14

Non è possibile "pingare direttamente" in JavaScript. Ci possono essere alcuni altri modi:

  • Ajax
  • Utilizzo di un'applet Java con isReachable
  • Scrivere uno script sul lato server che esegue il ping e utilizzare AJAX per comunicare con il server
  • Potresti anche essere in grado di eseguire il ping in flash (actionscript)

1
Java isReachable è abbastanza inaffidabile .... Ma bene è il 2018 e le applet Java sono comunque obsolete.
dreua,

8

Non è possibile eseguire il ping regolare nel browser Javascript, ma è possibile scoprire se il server remoto è attivo, ad esempio caricando un'immagine dal server remoto. Se il caricamento non riesce -> server inattivo.

Puoi persino calcolare il tempo di caricamento usando onload-event. Ecco un esempio su come utilizzare l'evento onload.


4
La cosa spiacevole è che i server che sto eseguendo il ping non sono server web. Sono server di gioco.
Chuck Callebs,

1
Quindi devi eseguire il ping sul lato server o potresti prendere in considerazione un server http leggero.
Epeli,

Conosci un modo per eseguire ping aggregati? Questo è il mio rallentamento principale, in attesa che una richiesta termini prima che inizi l'altra.
Chuck Callebs,

È necessario eseguire il ping dei server contemporaneamente. Puoi farlo con select, thread o processi. Per una soluzione davvero hardcore potresti usare Eventmachine.
Epeli,

1
Potresti cercare di trarre vantaggio dal comando da riga di pingcomando. È forza industriale. Oppure, ci sono tutti i tipi di app gratuite / open-source per monitorare se un host è in esecuzione, utilizzando vari tipi di controlli del battito cardiaco.
l'Uomo di latta il

7

Presentazione con una soluzione 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);
}

La isUp();chiamata non dovrebbe essere onopengestita dall'evento? :)
jave.web,

1
Utilizza il protocollo websocket ma presuppone che in realtà non ci sia un server websocket in attesa di una connessione. Questo è solo per il ping "qualsiasi vecchio IP".
Antony Woods,

Ma come è possibile rilevare se WebSocket non è supportato o se si è verificato davvero un errore? :)
jave.web,

Se pensi che sarai abbastanza sfortunato da eseguire il ping di un IP che potrebbe accettare una connessione websocket sulla porta 80, quindi sì, dovresti anche aggiungere isUp();a quel callback. O mitigalo aggiungendo una porta distintamente non websocket-y.
Antony Woods,

Ho votato a favore perché sono venuto qui alla ricerca di una soluzione a ciò che accade quando il server WebSocket viene riavviato e questa risposta mi ha mostrato che potevo impostare Timeout nel gestore degli errori del socket e tentare di riconnettermi (attesa di occupato). Probabilmente non è la migliore pratica, ma risolve il mio problema. :)
mynameisnafe

6

Per mantenere veloci le tue richieste, memorizza nella cache i risultati sul lato server del ping e aggiorna il file ping o il database ogni paio di minuti (o per quanto preciso tu voglia che sia). Puoi usare cron per eseguire un comando shell con i tuoi 8 ping e scrivere l'output in un file, il server web includerà questo file nella tua vista.


Penso che questo sia il modo più affidabile con il migliore possibile per un risultato accurato. Tuttavia, poiché richiede ancora alcuni lavori sul server, direi che non è un modo intelligente.
Chetabahana,

5

Se quello che stai cercando di vedere è se il server "esiste", puoi utilizzare quanto segue:

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

Ciò restituirà un'indicazione vero / falso se il server esiste.

Se vuoi tempo di risposta, una leggera modifica farà:

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

L'utilizzo è quindi banale:

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

O:

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

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia.
vonbrand,

1
questa è un'ottima soluzione, ma sfortunatamente il servizio di query del dominio yahoo sembra dare risultati variabili. ad esempio se provi i seguenti URL, begin-download .com beginfreedownload .com tornano come non registrati, ma se vai a quegli URL, sono chiaramente registrati. qualche idea di cosa sta succedendo qui? (Ho aggiunto uno spazio ai nomi di dominio in questi esempi, solo per evitare di distribuire succo di Google. Nel mio test non avevo uno spazio in loro)
user280109

Stai facendo una richiesta a Yahoo! API, il ping non sarà lo stesso se fai una richiesta dal tuo computer. Questo non ha senso
Andre Figueiredo,

Questa causa No 'Access-Control-Allow-Origin' header is present on the requested resource. Origine il callback di successo non vengono mai chiamati
vladkras il

4

Il problema con i ping standard è che sono ICMP, che molti posti non lasciano passare per motivi di sicurezza e traffico . Questo potrebbe spiegare il fallimento.

Ruby prima dell'1.9 aveva un TCP-based ping.rb, che funzionerà con Ruby 1.9+. Tutto quello che devi fare è copiarlo dall'installazione 1.8.7 da qualche altra parte. Ho appena confermato che avrebbe funzionato eseguendo il ping del mio router di casa.


4

Ci sono molte risposte folli qui e soprattutto su CORS -

È possibile eseguire una richiesta HTTP HEAD (come GET ma senza payload). Vedi https://ochronus.com/http-head-request-good-uses/

NON ha bisogno di un controllo preliminare, la confusione è dovuta a una vecchia versione delle specifiche, vedi Perché una richiesta HEAD di origine incrociata richiede un controllo di verifica preliminare?

Quindi potresti usare la risposta sopra che sta usando la libreria jQuery (non l'ho detto) ma con

type: 'HEAD'

--->

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

Ovviamente puoi anche usare vanilla js o dojo o qualsiasi altra cosa ...


1
L'invio della richiesta HEAD continua a non riuscire con "XMLHttpRequest non può caricare l'IP. Nessuna intestazione 'Access-Control-Allow-Origin' è presente sulla risorsa richiesta. L'origine 'ip2' non può quindi accedere." Così bloccato da CORS. Riceverai successo con lo stato http 0 e non sarai quindi in grado di differenziarlo da net :: ERR_CONNECTION_REFUSED per esempio
Martin Vysny,

0

Non so quale versione di Ruby stai utilizzando, ma hai provato a implementare il ping per ruby ​​anziché javascript? http://raa.ruby-lang.org/project/net-ping/


Sì, ci ho provato ma i ping sono sempre tornati falsi, indipendentemente dal server web. L'ho cambiato per usare solo la ping server.comsintassi.
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)
});;

se lo esegui con il nodo, la console registrerebbe 200 a condizione che Google non sia inattivo.


no, non è ... 1) ti manca, 2) sta tornando 301 Spostato in modo permanente: 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);
    }
  });
};

usare così:

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

-4

È possibile eseguire il comando ping.exe DOS da javaScript utilizzando il seguente:

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

È questo ciò che è stato chiesto o mi sto perdendo qualcosa?


4
Questo funzionerà solo su IE purtroppo e solo su un server Windows. Un'opzione migliore sarebbe utilizzare AJAX per eseguire uno script lato server.
Andrew Grothe,

Che diamine? Gli oggetti Active X possono essere eseguiti nel file system dell'utente (in IE su win server)? Non avevo lavorato con ActiveX ma non immaginavo che ...
Julix il

-6

basta sostituire

file_get_contents

con

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

1
Dovresti modificare la tua risposta precedente invece di aggiungere una nuova "parziale".
Artemix,

-8

Potrebbe essere molto più semplice di tutto ciò. Se vuoi che la tua pagina venga caricata, verifica la disponibilità o il contenuto di alcune pagine straniere per attivare altre attività della pagina Web, puoi farlo utilizzando solo javascript e php in questo modo.

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>

Questo dovrebbe farlo.

Il javascript attivato dovrebbe includere clearInterval (stopmelater)

Fammi sapere se per te va bene

Jerry


2
Come ho detto prima, questi non sono server Web che sto eseguendo il ping. Questi sono server di gioco. Non risponderanno alle richieste HTTP. :(
Chuck Callebs

amico, basta sostituire file_get_contents con
Jerry Wickey il

$ ip = $ _SERVER ['127.0.0.1']; exec ("ping -n 4 $ ip 2> & 1", $ output, $ retval); if ($ retval! = 0) {echo "no!"; } else {echo "sì!"; }
Jerry Wickey,

4
Questa non è una domanda PHP. Questa è una domanda JavaScript. Non uso PHP.
Chuck Callebs,

1
Non utilizzare firme o slogan nei tuoi post, altrimenti verranno rimossi. Vedi le FAQ per i dettagli.
Artemix,

-13

Potresti provare a usare PHP nella tua pagina web ... qualcosa del genere:

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

?>

Questo non è testato quindi potrebbe avere errori di battitura ecc ... ma sono sicuro che funzionerebbe. Potrebbe essere migliorato anche ...


5
Secondo i tag dell'OP questa è in realtà una domanda su Ruby on Rails, quindi usare PHP non è una buona soluzione.
Tin Man il

1
Non iniziare una discussione qui, ma il punto di questo forum non è di aiuto?
Chris,

5
@Chris Lo è, ma che tipo di aiuto hai dato a OP che utilizza Ruby e JS nella sua applicazione fornendo codice PHP?
biphobe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.