190 votes

Est-il possible de pinguer un serveur depuis Javascript ?

Je suis en train de créer une application web qui nécessite que je vérifie si des serveurs distants sont en ligne ou non. Lorsque je l'exécute à partir de la ligne de commande, mon temps de chargement de la page atteint jusqu'à 60 secondes (pour 8 entrées, il augmentera de façon linéaire avec plus).

J'ai décidé d'opter pour la solution de ping sur l'ordinateur de l'utilisateur. De cette façon, je peux charger la page et leur faire simplement attendre les données "le serveur est en ligne" pendant qu'ils parcourent mon contenu.

Si quelqu'un a la réponse à la question ci-dessus, ou s'ils connaissent une solution pour maintenir mes temps de chargement de page rapide, j'apprécierais vraiment.

161voto

Chuck Callebs Points 8084

J'ai trouvé quelqu'un qui réalise cela avec une utilisation très astucieuse de l'objet natif Image.

D'après leur source, voici la fonction principale (elle dépend d'autres parties de la source mais vous avez l'idée).

function Pinger_ping(ip, rappel) {

  if(!this.inUse) {

    this.inUse = true;
    this.rappel = rappel
    this.ip = ip;

    var _that = this;

    this.img = new Image();

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

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

  }
}

Cela fonctionne sur tous les types de serveurs que j'ai testés (serveurs web, serveurs FTP et serveurs de jeu). Cela fonctionne également avec les ports. Si quelqu'un rencontre un cas d'utilisation qui échoue, veuillez poster dans les commentaires et je mettrai à jour ma réponse.

Mise à jour : Le lien précédent a été supprimé. Si quelqu'un trouve ou implémente ce qui précède, veuillez commenter et je l'ajouterai à la réponse.

Mise à jour 2 : @trante a eu la gentillesse de fournir un jsFiddle.

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

Mise à jour 3 : @Jonathon a créé un dépôt GitHub avec la mise en œuvre.

https://github.com/jdfreder/pingjs

Mise à jour 4 : Il semble que cette mise en œuvre ne soit plus fiable. Des personnes signalent également que Chrome ne le prend plus en charge du tout, renvoyant une erreur net::ERR_NAME_NOT_RESOLVED. Si quelqu'un peut vérifier une solution alternative, je la mettrai comme réponse acceptée.

56 votes

Ceci est ce que j'ai utilisé. Cela a cependant un défaut, et c'est que l'"image" est mise en cache. Lorsque je ping un IP donné initialement, j'obtiens 304 ms - mais si je le ping une deuxième fois sans recharger la page, j'obtiens 2 ms à la place. Cela pourrait être évité en ajoutant une "/?cachebreaker="+new Date().getTime(); à la fin de l'attribut src de l'image si nécessaire.

0 votes

Bonne prise. J'ai en fait remarqué cela, mais j'ai tout simplement supposé que c'était inévitable. Ajouter un slug à la fin devrait certainement le corriger.

0 votes

Un autre exemple utilisant l'approche de l'image est décrit ici

30voto

Nils Holgersson Points 51

Ping est ICMP, mais si un port TCP ouvert existe sur le serveur distant, cela pourrait être réalisé comme suit :

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) {
    // c'est prévu
  }

}

1 votes

J'aime cette solution astucieuse. Devoir fournir une fonction pour pong au lieu de retourner un nombre est un peu bizarre pour moi mais fonctionne.

0 votes

@armen: vous devez fournir une fonction en tant que troisième argument à ping(), la valeur de cet argument est appelée pong dans la fonction.

5 votes

ping("example.com", "77", function(m){ console.log("Cela a pris "+m+" millisecondes."); }) .....appel d'exemple

20voto

jerjer Points 5585

Vous pouvez essayer ceci :

mettez ping.html sur le serveur avec ou sans aucun contenu, sur le javascript faites la même chose que ci-dessous :

    function ping(){
       $.ajax({
          url: 'ping.html',
          success: function(result){
             alert('réponse');
          },     
          error: function(result){
              alert('timeout/erreur');
          }
       });
    }

1 votes

Les serveurs sur lesquels je fais des ping ne sont pas les miens, donc je n'ai pas cette option. Merci quand même.

10 votes

@dlchambers Pas dû à CORS mais EN RAISON de la politique de domaine croisé. CORS permet à un serveur de spécifier les origines plus il doit être pris en charge par le navigateur. c'est donc plus comme un problème de domaine croisé.

0 votes

Les requêtes de type HEAD ne fonctionneront pas en raison de CORS non plus. Testé avec Chromium 55. Recevoir la même erreur avec le code http 0 comme dans le cas de net::CONNECTION_REFUSED par exemple.

15voto

user389823 Points 2406

Vous ne pouvez pas "ping" directement en javascript. Il existe peut-être quelques autres façons :

  • Ajax
  • Utiliser une applet Java avec isReachable
  • Écrire un script côté serveur qui pingue et utiliser AJAX pour communiquer avec votre script côté serveur
  • Vous pourriez également être en mesure de pinguer en flash (actionscript)

3 votes

La fonction estReachable de Java est assez peu fiable.... Mais bon, nous sommes en 2018 et les applets Java sont de toute façon obsolètes.

7voto

user456733 Points 301

Pour maintenir la rapidité de vos requêtes, mettez en cache les résultats côté serveur du ping et mettez à jour le fichier ou la base de données du ping toutes les quelques minutes (ou aussi précisément que vous le souhaitez). Vous pouvez utiliser cron pour exécuter une commande shell avec vos 8 pings et écrire la sortie dans un fichier, le serveur Web inclura ce fichier dans votre vue.

0 votes

Je pense que c'est le moyen le plus fiable et le plus efficace pour obtenir des résultats précis. Cependant, comme cela nécessite encore quelques travaux sur le serveur, je dirais que ce n'est pas une façon intelligente de procéder.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X