Apakah mungkin melakukan ping server dari Javascript?

152

Saya membuat aplikasi web yang mengharuskan saya memeriksa untuk melihat apakah server jarak jauh sedang online atau tidak. Ketika saya menjalankannya dari baris perintah, beban halaman saya mencapai 60-an penuh (untuk 8 entri, itu akan skala secara linear dengan lebih banyak).

Saya memutuskan untuk pergi rute ping di ujung pengguna. Dengan cara ini, saya dapat memuat halaman dan meminta mereka menunggu data "server online" saat menjelajahi konten saya.

Jika ada yang punya jawaban untuk pertanyaan di atas, atau jika mereka tahu solusi untuk menjaga halaman saya cepat, saya pasti akan menghargainya.

Chuck Callebs
sumber

Jawaban:

134

Saya telah menemukan seseorang yang menyelesaikan ini dengan penggunaan Imageobjek asli yang sangat pintar .

Dari sumbernya, ini adalah fungsi utama (memiliki ketergantungan pada bagian lain dari sumber tetapi Anda mendapatkan ide).

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

  }
}

Ini berfungsi pada semua jenis server yang telah saya uji (server web, server ftp, dan server game). Ini juga berfungsi dengan port. Jika ada yang menemukan kasus penggunaan yang gagal, silakan kirim komentar dan saya akan memperbarui jawaban saya.

Pembaruan : Tautan sebelumnya telah dihapus. Jika ada yang menemukan atau mengimplementasikan hal di atas, silakan komentar dan saya akan menambahkannya ke dalam jawabannya.

Pembaruan 2 : @trante cukup baik untuk menyediakan jsFiddle.

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

Pembaruan 3 : @ Jonathon membuat repo GitHub dengan implementasinya.

https://github.com/jdfreder/pingjs

Pembaruan 4 : Sepertinya implementasi ini tidak lagi dapat diandalkan. Orang-orang juga melaporkan bahwa Chrome tidak lagi mendukung semuanya, membuat net::ERR_NAME_NOT_RESOLVEDkesalahan. Jika seseorang dapat memverifikasi solusi alternatif saya akan menempatkan itu sebagai jawaban yang diterima.

Chuck Callebs
sumber
48
Ini yang saya gunakan. Namun memang memiliki satu kelemahan, dan itu adalah bahwa "gambar" di-cache. Ketika saya melakukan ping IP yang diberikan pada awalnya, saya mendapatkan 304 ms - tetapi jika saya melakukan ping untuk kedua kalinya tanpa memuat ulang halaman, saya mendapatkan 2 ms sebagai gantinya. Ini bisa dihindari dengan menambahkan a "/?cachebreaker="+new Date().getTime();ke akhir img src jika perlu.
Meshaal
2
ini tidak berfungsi untuk saya, hasil hostname buruk yang diketahui dalam permintaan Ping tidak dapat menemukan host .... tetapi karena satu kesalahan adalah 'baik' hal ini dikatakan merespon
Maslow
5
Lebih banyak pengujian mengungkapkan bahwa ini sama sekali tidak dapat diandalkan.
Leo
2
Ping API yang dibuat @Jonathon akan berhasil melakukan ping segalanya. Situs yang tidak ada dan karakter acak.
IE5Master
2
Ping API sebenarnya selalu gagal dengan satu kesalahan. NAMUN jika URL target menunjukkan sebuah gambar, URL itu akan memuat yang luar biasa! Bypass cek CORS.
Martin Vysny
20

Ping adalah ICMP, tetapi jika ada port TCP terbuka pada server jarak jauh itu dapat dicapai seperti ini:

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
sumber
Saya suka solusi rumit ini. Harus menyediakan fungsi untuk pong alih-alih mengembalikan nomor agak aneh bagi saya tetapi bisa diterapkan.
Nick
@armen: Anda harus menyediakan fungsi sebagai argumen ketiga ke ping (), nilai argumen ini disebut pong di dalam fungsi.
finitud
2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); })..... contoh panggilan
jave.web
@Nick: Ini adalah hal yang tidak sinkron, jadi pada saat metode kembali, onreadystatechangebelum dipecat. Ini berarti Anda memerlukan panggilan balik untuk mengambil ketika keadaan berubah.
awe
Apa pun yang saya pilih untuk tuan rumah, pong () dipanggil. ping ( test.zzzzzzzzz, "77", function (m) {console.log ("Butuh" + m + "miliseconds.");}) mencetak "Butuh 67 miliseconds." ping ( stackoverflow.com, "80", function (m) {console.log ("Butuh" + m + "miliseconds.");}) memberikan CORS-Error: developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Kesalahan / ... Saya tidak melihat bagaimana saya dapat memeriksa dengan kode ini jika komputer jarak jauh sedang online.
Tux
18

Anda dapat mencoba ini:

letakkan ping.html di server dengan atau tanpa konten apa pun, pada javascript lakukan hal yang sama seperti di bawah ini:

<script>
    function ping(){
       $.ajax({
          url: 'ping.html',
          success: function(result){
             alert('reply');
          },     
          error: function(result){
              alert('timeout/error');
          }
       });
    }
</script>
jerjer
sumber
1
Server yang saya ping bukan milik saya, jadi saya tidak memiliki opsi itu. Terimakasih Meskipun.
Chuck Callebs
9
@ dlchambers Bukan karena CORS tetapi AKIBAT lintas domain poilicy. CORS memungkinkan server menentukan asal dan ditambah harus didukung oleh browser. jadi lebih seperti masalah lintas domain.
Royi Namir
Permintaan tipe HEAD tidak akan berfungsi karena CORS juga. Diuji dengan Chromium 55. Menerima kesalahan yang sama dengan kode http 0 seperti dalam kasus net :: CONNECTION_REFUSED misalnya.
Martin Vysny
Ini lebih lintas peramban firendly.
Gabriel
14

Anda tidak dapat "ping" secara langsung dalam javascript. Mungkin ada beberapa cara lain:

  • Ajax
  • Menggunakan applet java dengan isReachable
  • Menulis skrip sisi server yang ping dan menggunakan AJAX untuk berkomunikasi dengan skrip server Anda
  • Anda mungkin juga dapat melakukan ping di flash (actioncript)
Eugene
sumber
1
Java's isReachable cukup tidak bisa diandalkan .... Tapi yah, ini 2018 dan Java Applet sudah ketinggalan zaman.
dreua
8

Anda tidak dapat melakukan ping biasa di browser Javascript, tetapi Anda dapat mengetahui apakah server jauh masih hidup dengan misalnya memuat gambar dari server jauh. Jika memuat gagal -> server turun.

Anda bahkan dapat menghitung waktu pemuatan dengan menggunakan onload-event. Berikut adalah contoh cara menggunakan acara onload.

Epeli
sumber
4
Yang disayangkan tentang itu adalah server yang saya ping bukan server web. Mereka adalah server game.
Chuck Callebs
1
Maka Anda harus melakukan ping di sisi server - atau Anda dapat mempertimbangkan beberapa http-server ringan.
Epeli
Apakah Anda tahu cara melakukan ping agregat? Itulah perlambatan utama saya, menunggu satu permintaan selesai sebelum yang lain dimulai.
Chuck Callebs
Anda perlu melakukan ping ke server secara bersamaan. Anda dapat mencapainya dengan memilih, utas atau proses. Untuk solusi yang benar-benar hardcore, Anda dapat menggunakan Eventmachine.
Epeli
1
Anda mungkin melihat mengambil keuntungan dari perintah command-line ping. Ini kekuatan industri. Atau, ada segala macam aplikasi gratis / sumber terbuka untuk dipantau jika host berjalan, menggunakan berbagai jenis pemeriksaan detak jantung.
the Tin Man
7

Masuk dengan solusi 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);
}
Antony Woods
sumber
Bukankah seharusnya isUp();panggilan itu ada dalam onopenevent handler? :)
jave.web
1
Ia menggunakan protokol websocket tetapi menganggap sebenarnya tidak ada server websocket yang menunggu koneksi. Ini hanya untuk melakukan ping 'IP lama'.
Antony Woods
Tetapi bagaimana Anda bisa mendeteksi apakah WebSocket tidak didukung atau memang ada kesalahan? :)
jave.web
Jika Anda merasa cukup beruntung untuk melakukan ping IP yang dapat menerima koneksi websocket pada port 80, maka ya, Anda juga harus menambahkan isUp();ke callback itu. Atau kurangi dengan menambahkan port non-websocket-y yang jelas.
Antony Woods
Saya memilih ini karena saya datang ke sini mencari solusi untuk apa yang terjadi ketika server websocket saya di-boot ulang, dan jawaban ini menunjukkan bahwa saya dapat mengatur TimeTime di penangan kesalahan soket dan mencoba untuk menyambung kembali (menunggu sibuk). Mungkin bukan praktik terbaik, tapi selesaikan masalah saya. :)
mynameisnafe
6

Untuk menjaga agar permintaan Anda tetap cepat, cache hasil sisi server dari ping dan perbarui file ping atau database setiap beberapa menit (atau betapapun akuratnya Anda inginkan). Anda dapat menggunakan cron untuk menjalankan perintah shell dengan 8 ping Anda dan menulis hasilnya menjadi file, server web akan memasukkan file ini ke dalam tampilan Anda.

pengguna456733
sumber
Saya pikir ini adalah cara yang paling dapat diandalkan dengan hasil terbaik untuk hasil yang akurat. Namun karena masih memerlukan beberapa pekerjaan di server saya akan mengatakan itu bukan cara yang cerdas.
Chetabahana
5

Jika yang ingin Anda lihat adalah apakah server "ada", Anda dapat menggunakan yang berikut:

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

Ini akan mengembalikan indikasi benar / salah apakah server ada.

Jika Anda ingin waktu respons, sedikit modifikasi akan dilakukan:

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

Penggunaannya kemudian sepele:

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

Atau:

var responseInMillis = ping("example.com");
alert(responseInMillis);
Ohad
sumber
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah.
vonbrand
1
ini adalah solusi yang bagus, tetapi sayangnya, layanan permintaan domain yahoo tampaknya memberikan hasil yang bervariasi. misalnya jika Anda mencoba URL berikut, mulai-unduh .com beginfreedownload .com mereka kembali sebagai tidak terdaftar, tetapi jika Anda pergi ke URL tersebut, mereka jelas terdaftar. ada ide apa yang terjadi di sini? (Saya telah menambahkan spasi ke nama domain dalam contoh ini, hanya untuk menghindari membagikan jus Google. Dalam pengujian saya, saya tidak punya spasi di dalamnya)
user280109
Anda sedang melakukan permintaan ke Yahoo! API, ping tidak akan sama jika Anda melakukan permintaan dari mesin Anda. Ini tidak masuk akal
Andre Figueiredo
Ini penyebab No 'Access-Control-Allow-Origin' header is present on the requested resource. Origindan keberhasilan callback tidak pernah disebut
vladkras
4

Masalah dengan ping standar adalah mereka ICMP, yang banyak tempat tidak membiarkan karena alasan keamanan dan lalu lintas . Itu mungkin menjelaskan kegagalan.

Ruby sebelum 1.9 memiliki berbasis TCP ping.rb, yang akan berjalan dengan Ruby 1.9+. Yang harus Anda lakukan adalah menyalinnya dari instalasi 1.8.7 ke tempat lain. Saya baru saja mengkonfirmasi bahwa itu akan berjalan dengan melakukan ping router rumah saya.

Manusia Timah
sumber
4

Ada banyak jawaban gila di sini dan terutama tentang CORS -

Anda dapat melakukan permintaan HEAD http (seperti MENDAPAT tapi tanpa muatan). Lihat https://ochronus.com/http-head-request-good-uses/

TIDAK memerlukan pemeriksaan preflight, kebingungannya adalah karena versi spesifikasi yang lama, lihat Mengapa permintaan HEAD lintas-asal memerlukan pemeriksaan preflight?

Jadi Anda bisa menggunakan jawaban di atas yang menggunakan perpustakaan jQuery (tidak mengatakannya) tetapi dengan

type: 'HEAD'

--->

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

Tentunya Anda juga dapat menggunakan vanilla js atau dojo atau apa pun ...

sebilasse
sumber
1
Mengirim permintaan HEAD masih gagal dengan "XMLHttpRequest tidak dapat memuat IP. Tidak ada tajuk 'Access-Control-Allow-Origin' hadir pada sumber daya yang diminta. Karena itu Origin 'ip2' tidak diizinkan mengakses." Jadi diblokir oleh CORS. Anda akan menerima kesuksesan dengan status http 0, dan karenanya Anda tidak akan dapat membedakannya dari jaring :: ERR_CONNECTION_REFUSED misalnya
Martin Vysny
0

Saya tidak tahu versi Ruby apa yang Anda jalankan, tetapi sudahkah Anda mencoba menerapkan ping untuk ruby ​​alih-alih javascript? http://raa.ruby-lang.org/project/net-ping/

wajiw
sumber
Ya, saya sudah mencobanya tetapi ping selalu kembali palsu, terlepas dari server web. Saya mengubahnya hanya menggunakan ping server.comsintaks.
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)
});;

jika Anda menjalankan ini dengan node itu akan menghibur log 200 selama google tidak down.

LifterCoder
sumber
tidak, itu bukan ... 1) Anda tidak membutuhkan, 2) itu kembali 301 Pindah Secara Permanen: 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);
    }
  });
};

gunakan seperti ini:

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

Anda dapat menjalankan perintah DOS ping.exe dari javaScript menggunakan folowing:

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

Apakah ini yang diminta, atau saya kehilangan sesuatu?

Garryg
sumber
4
Sayangnya ini hanya akan berfungsi pada IE dan hanya pada Windows Server. Opsi yang lebih baik adalah menggunakan AJAX untuk menjalankan skrip sisi server.
Andrew Grothe
Apa apaan? Objek X aktif dapat mengeksekusi di sistem file pengguna (di IE pada win server)? Saya tidak pernah bekerja dengan ActiveX tetapi tidak membayangkan itu ...
Julix
-6

ganti saja

file_get_contents

dengan

$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
sumber
1
Anda harus mengedit jawaban Anda sebelumnya alih-alih menambahkan jawaban 'parsial' baru.
Artemix
-8

Mungkin jauh lebih mudah dari semua itu. Jika Anda ingin memuat halaman Anda kemudian memeriksa ketersediaan atau konten beberapa halaman asing untuk memicu aktivitas halaman web lain, Anda bisa melakukannya hanya menggunakan javascript dan php seperti ini.

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>

Itu harus dilakukan.

Javascript yang dipicu harus menyertakan clearInterval (stopmelater)

Beri tahu saya jika itu berhasil untuk Anda

Jerry

Jerry Wickey
sumber
2
Seperti yang saya katakan sebelumnya, ini bukan server web yang saya ping. Ini adalah server permainan. Mereka tidak akan menanggapi permintaan HTTP. :(
Chuck Callebs
Bung, ganti saja file_get_contents dengan
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
Ini bukan pertanyaan PHP. Ini adalah pertanyaan JavaScript. Saya tidak menggunakan PHP.
Chuck Callebs
1
Tolong jangan gunakan tanda tangan atau tagline di posting Anda, atau mereka akan dihapus. Lihat FAQ untuk detailnya.
Artemix
-13

Anda dapat mencoba menggunakan PHP di halaman web Anda ... sesuatu seperti ini:

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

?>

Ini tidak diuji sehingga mungkin memiliki kesalahan ketik dll ... tapi saya yakin itu akan berhasil. Dapat ditingkatkan juga ...

Chris
sumber
5
Menurut tag OP, ini sebenarnya adalah pertanyaan Ruby on Rails, jadi menggunakan PHP bukanlah solusi yang baik.
the Tin Man
1
Bukan untuk memulai argumen di sini, tetapi bukankah gunanya forum ini membantu?
Chris
5
@ Chris Memang, tapi bantuan apa yang Anda berikan kepada OP yang menggunakan Ruby dan JS di applicatoinnya dengan memasok kode PHP?
biphobe