Чи можливо пінг-сервер з Javascript?


152

Я роблю веб-додаток, який вимагає перевірити, чи віддалені сервери в Інтернеті чи ні. Коли я запускаю його з командного рядка, завантаження моєї сторінки збільшується до повних 60-х (для 8 записів вона буде лінійно масштабуватися з більшою кількістю).

Я вирішив піти маршрутом пінг на кінець користувача. Таким чином, я можу завантажити сторінку і просто змусити їх чекати даних "сервер в мережі" під час перегляду мого вмісту.

Якщо хтось має відповідь на вищезазначене питання, або якщо вони знають рішення, щоб швидше завантажувати мою сторінку, я б точно оцінив це.

Відповіді:


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

  }
}

Це працює на всіх тестованих серверах (веб-серверах, 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, я отримую 304 мс, але якщо я вдруге запитую його без перезавантаження сторінки, я отримую 2 мс замість цього. Цього можна уникнути, "/?cachebreaker="+new Date().getTime();якщо необхідно, додавши a до кінця img src.
Мешал

2
це не працює для мене, невідомі результати поганого імені хоста у запиті Ping не змогли знайти хоста .... але оскільки onerror "хороший", ця річ говорить, що він відповів
Maslow

5
Більше тестування показало, що це абсолютно ненадійно.
Лев

2
API Ping, який створив @Jonathon, успішно простежить усе. Сайти, яких не існує, та випадкові символи.
IE5Master

2
API Ping насправді завжди виходить з ладу onerror. ЗАРАЗ, якщо цільова URL-адреса позначає зображення, воно запускає завантаження, яке є приголомшливим! Обходить чеки CORS.
Мартін Висний

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
  }

}


Мені подобається це хитре рішення. Необхідність надати функцію для понг замість повернення числа для мене трохи дивна, але працездатна.
Нік

@armen: ви повинні надати функцію в якості третього аргументу ping (), значення цього аргументу називається pong у межах функції.
фініш

2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); })..... приклад дзвінка
jave.web

@ Nick: Це асинхронний матеріал, тому під час повернення методу onreadystatechangeще не запустили. Це означає, що вам потрібен зворотний дзвінок, щоб забрати його, коли стан зміниться.
трепет

Що б я не вибрав для хоста, називається pong (). ping ( test.zzzzzzzzz, "77", функція (m) {console.log ("На це пішло" + m + "мілісекунди.");}) друкує "На це пішло 67 мілісекунд." ping ( stackoverflow.com, "80", функція (m) {console.log ("На це пішло" + m + "мілісекунди.");}) дає CORS-помилку: developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Помилки /… Я не бачу, як я можу перевірити цей код, якщо віддалений комп'ютер в мережі.
Тукс

18

ви можете спробувати це:

поставте ping.html на сервер із вмістом або без нього, на javascript зробіть так, як нижче:

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

1
Сервери, за якими я питую, не є моїми власними, тому у мене немає такої можливості. Спасибі, хоча.
Чак Каллебс

9
@dlchambers Не зобов’язаний CORS, але ДОВІДКОВА, щоб перехрестити домен poilicy. CORS дозволяє серверу вказувати джерела, плюс його повинен підтримувати браузер. тож це більше нагадує проблему перехресного домену.
Рой Намір

Запити типу HEAD також не працюватимуть через CORS. Тестований з Chromium 55. Отримання такої ж помилки з http-кодом 0, як і у випадку net :: CONNECTION_REFUSED, наприклад.
Мартін Висний

Це більше крос-браузера firendly.
Габріель

14

Ви не можете безпосередньо "ping" в JavaScript. Можливо кілька інших способів:

  • Аякс
  • Використання аплету Java з isReachable
  • Написання сценарію на сервері, який пінг і використання AJAX для спілкування з вашим сервером
  • Можливо, ви також зможете пінг-флеш у спалах (сценарій дій)

1
Java isReachable є досить ненадійним .... Але добре, що це 2018 рік, а Java-аплети все одно застаріли.
dreua

8

Ви не можете робити звичайний пінг в браузері Javascript, але ви можете дізнатися, чи віддалений сервер живий, наприклад, завантаживши зображення з віддаленого сервера. Якщо завантаження не вдається -> сервер не працює.

Ви навіть можете розрахувати час завантаження, використовуючи onload-event. Ось приклад використання події завантаження.


4
Невдача в тому, що сервери, за якими я пінг, - це не веб-сервери. Вони ігрові сервери.
Чак Каллебс

1
Тоді вам доведеться виконати пінгінг на стороні сервера - або ви можете розглянути якийсь легкий http-сервер.
Епелі

Чи знаєте ви, як зробити агрегатні пінгви? Це моє основне уповільнення, чекаючи, коли закінчиться один запит, перш ніж розпочнеться інший.
Чак Каллебс

Вам потрібно одночасно пінг-сервери. Ви можете досягти цього за допомогою вибору, потоків або процесів. Для дійсно жорсткого рішення ви можете використовувати Eventmachine.
Епелі

1
Ви можете скористатися командою командного рядка ping. Це промислова міцність. Або є всілякі безкоштовні програми з відкритим кодом, щоб відстежувати, чи працює хост, використовуючи різні типи перевірок серцебиття.
Людина з жерсті

7

Підключення за допомогою рішення веб-розетки ...

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 не чекає на з'єднання. Це лише для того, щоб пінгнути "будь-який старий IP".
Антоні Вудс

Але як ви можете виявити, чи WebSocket просто не підтримується чи дійсно була помилка? :)
jave.web

Якщо ви думаєте, що вам не пощастить надіслати IP-адресу, яка може прийняти з'єднання веб-сокетів на порт 80, то так, вам також слід додати isUp();до цього зворотного дзвінка. Або пом'якшити це, додавши чітко не-websocket-y порт.
Ентоні Вудс

Я проголосував за це, тому що я прийшов сюди шукати рішення того, що станеться, коли мій сервер веб-сокетів перезавантажиться, і ця відповідь показала мені, що я можу встановити тайм-аут в обробці помилок сокета і спробувати знову підключитися (зайняте очікування). Можливо, це не найкраща практика, але вирішує моє питання. :)
mynameisnafe

6

Щоб швидко зберігати ваші запити, кешуйте результати сервера ping на керуванні сервером та оновлюйте файл або базу даних ping кожні пару хвилин (або наскільки це точно ви хочете). Ви можете використовувати cron, щоб запустити команду оболонки з вашими 8 пінгами і записати вихід у файл, веб-сервер включить цей файл у ваше подання.


Я думаю, що це найнадійніший спосіб з найкращим можливим для точного результату. Однак оскільки це все ще вимагає деяких робіт на сервері, я б сказав, що це не розумний спосіб.
Четабахана

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

Хоча це посилання може відповісти на питання, краще включити сюди суттєві частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться.
фонбранд

1
це чудове рішення, але, на жаль, служба запитів домену Yahoo, здається, дає різні результати. Наприклад, якщо ви спробуєте такі URL-адреси, start-download .com beginfreedownload .com вони повертаються як не зареєстровані, але якщо ви переходите до цих URL-адрес, вони явно реєструються. якась ідея, що тут відбувається? (Я додав простір до доменних імен у цих прикладах, просто щоб уникнути видачі соку Google. У моєму тесті я не мав місця в них)
user280109

Ви робите запит до Yahoo! API, ping не буде однаковим, якщо ви зробите запит зі своєї машини. Це не має сенсу
Андре Фігейредо

Це викликає No 'Access-Control-Allow-Origin' header is present on the requested resource. Originі успіх зворотного виклику ніколи не називається
vladkras

4

Проблема зі стандартними пінгами полягає в їх ICMP, який багато місць не пропускають з міркувань безпеки та руху . Це може пояснити невдачу.

Рубін до 1.9 мав TCP на основі ping.rb, який буде працювати з Рубіном 1.9+. Все, що вам потрібно зробити, - скопіювати його з інсталяції 1.8.7 в інше місце. Я щойно підтвердив, що це буде працювати, пінгуючи домашній маршрутизатор.


4

Тут є безліч шалених відповідей, особливо про CORS -

Ви можете зробити HTAD-запит 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>

Звичайно, ви можете також використовувати ванільний js або доджо чи що завгодно ...


1
Відправлення запиту HEAD все ще не вдається, "XMLHttpRequest не може завантажити IP-адресу. На запитуваному ресурсі немає заголовка" Access-Control-Allow-Origin ". Походження" ip2 "не має доступу." Так заблокований CORS. Ви отримаєте успіх із статусом http 0, і таким чином ви не зможете відрізнити це від мережі :: ERR_CONNECTION_REFUSED, наприклад
Martin Vysny,

0

Я не знаю, яку версію Ruby ти працюєш, але ти спробував реалізувати ping для ruby ​​замість javascript? http://raa.ruby-lang.org/project/net-ping/


Так, я пробував це, але пінг завжди повертався помилковим, незалежно від веб-сервера. Я змінив його, щоб просто використовувати ping server.comсинтаксис.
Чак Каллебс

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

якщо запустити це за допомогою вузла, він консолює журнал 200 до тих пір, поки Google не вниз.


ні, це не ... 1) вам не вистачає вимагати, 2) повертається 301 Переїхав постійно: 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);
    }
  });
};

використовувати так:

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

-4

Ви можете запустити команду DOS ping.exe з javaScript за допомогою наступного:

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 для запуску сценарію на стороні сервера.
Ендрю Гроте

Якого біса? Активні об'єкти X можуть виконуватись у файловій системі користувача (в IE на сервері win)? Я не працював з ActiveX, але не уявляв цього ...
Джулікс


-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 (стопмелатер)

Дайте мені знати, чи це працює для вас

Джеррі


2
Як я вже говорив раніше, це не веб-сервери, на яких я пінг. Це ігрові сервери. Вони не відповідатимуть на запити HTTP. :(
Чак Каллебс

чувак, просто заміни file_get_contents на
Джеррі Вікі

$ ip = $ _SERVER ['127.0.0.1']; exec ("ping -n 4 $ ip 2> & 1", $ output, $ retval); if ($ retval! = 0) {echo "ні!"; } else {відлуння "так!"; }
Джеррі Вікі

4
Це не питання PHP. Це питання JavaScript. Я не використовую PHP.
Чак Каллебс

1
Будь ласка, не використовуйте підписи або теги в своїх публікаціях, інакше вони будуть видалені. Детальні відомості див. У розділі FAQ .
Артемікс

-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
Відповідно до тегів ОП, це насправді питання Ruby on Rails, тому використання PHP не є хорошим рішенням.
Олов'яний чоловік

1
Тут не починати аргументи, але чи не сенс цього форуму допомагати?
Кріс

5
@Chris Це так, але яку допомогу ви надали ОП, хто використовує Ruby та JS у своєму аплікатоїні, надаючи PHP-код?
біфоб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.