Có thể ping máy chủ từ Javascript không?


152

Tôi đang tạo một ứng dụng web yêu cầu tôi kiểm tra xem máy chủ từ xa có trực tuyến hay không. Khi tôi chạy nó từ dòng lệnh, tải trang của tôi tăng lên đến 60 giây (đối với 8 mục, nó sẽ mở rộng tuyến tính với nhiều hơn).

Tôi quyết định đi theo con đường ping đến cuối của người dùng. Bằng cách này, tôi có thể tải trang và chỉ cần họ chờ dữ liệu "máy chủ đang trực tuyến" trong khi duyệt nội dung của tôi.

Nếu bất cứ ai có câu trả lời cho câu hỏi trên hoặc nếu họ biết một giải pháp để giữ cho trang của tôi tải nhanh, tôi chắc chắn sẽ đánh giá cao nó.

Câu trả lời:


134

Tôi đã tìm thấy ai đó thực hiện điều này với cách sử dụng rất thông minh của Imageđối tượng bản địa .

Từ nguồn của họ, đây là chức năng chính (nó có sự phụ thuộc vào các phần khác của nguồn nhưng bạn có ý tưởng).

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

  }
}

Điều này hoạt động trên tất cả các loại máy chủ mà tôi đã thử nghiệm (máy chủ web, máy chủ ftp và máy chủ trò chơi). Nó cũng hoạt động với các cổng. Nếu bất cứ ai gặp phải trường hợp sử dụng không thành công, xin vui lòng gửi trong các ý kiến ​​và tôi sẽ cập nhật câu trả lời của tôi.

Cập nhật : Liên kết trước đã được gỡ bỏ. Nếu bất cứ ai tìm thấy hoặc thực hiện các điều trên, xin vui lòng bình luận và tôi sẽ thêm nó vào câu trả lời.

Cập nhật 2 : @trante đã đủ tốt để cung cấp jsFiddle.

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

Cập nhật 3 : @Jonathon đã tạo một repo GitHub với việc thực hiện.

https://github.com/jdfreder/pingjs

Cập nhật 4 : Có vẻ như việc triển khai này không còn đáng tin cậy nữa. Mọi người cũng báo cáo rằng Chrome không còn hỗ trợ tất cả, net::ERR_NAME_NOT_RESOLVEDgây ra lỗi. Nếu ai đó có thể xác minh một giải pháp thay thế, tôi sẽ đặt đó là câu trả lời được chấp nhận.


48
Đây là những gì tôi đã và đang sử dụng. Tuy nhiên, nó có một lỗ hổng và đó là "hình ảnh" được lưu trữ. Khi tôi ping một IP nhất định ban đầu, tôi nhận được 304 ms - nhưng nếu tôi ping nó lần thứ hai mà không tải lại trang, tôi nhận được 2 ms thay thế. Điều này có thể tránh được bằng cách nối thêm "/?cachebreaker="+new Date().getTime();phần cuối của img src nếu cần.
Meshaal

2
điều này không hiệu quả với tôi, một tên máy chủ xấu được biết đến trong yêu cầu Ping không thể tìm thấy máy chủ .... nhưng vì onerror là 'tốt' nên điều này nói rằng nó đã phản hồi
Maslow

5
Nhiều thử nghiệm cho thấy điều này là hoàn toàn không đáng tin cậy.
Leo

2
API Ping mà @Jonathon tạo ra sẽ ping thành công mọi thứ. Các trang web không tồn tại và các ký tự ngẫu nhiên.
IE5Master

2
API Ping thực sự luôn luôn thất bại với onerror. TUY NHIÊN nếu URL mục tiêu biểu thị một hình ảnh, nó kích hoạt tải rất tuyệt vời! Bỏ qua kiểm tra CORS.
Martin Vysny

20

Ping là ICMP, nhưng nếu có bất kỳ cổng TCP mở nào trên máy chủ từ xa thì có thể đạt được như thế này:

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
  }

}


Tôi thích giải pháp khó khăn này. Phải cung cấp một chức năng cho pong thay vì trả lại một số là một số lẻ đối với tôi nhưng hoàn toàn khả thi.
Nick

@armen: bạn phải cung cấp một hàm làm đối số thứ ba cho ping (), giá trị của đối số này được gọi là pong trong hàm.
thúc

2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); })..... ví dụ cuộc gọi
jave.web

@Nick: Đây là công cụ không đồng bộ, vì vậy tại thời điểm phương thức trả về, onreadystatechangenó chưa được kích hoạt. Điều này có nghĩa là bạn cần gọi lại để nhận khi trạng thái thay đổi.
kinh ngạc

Bất cứ điều gì tôi chọn cho máy chủ, pong () được gọi. ping ( test.zzzzzzzzz, "77", function (m) {console.log ("Mất" + m + "miliseconds.");}) in In Nó mất 67 triệu giây. ping ( stackoverflow.com, "80", function (m) {console.log ("Mất" + m + "miliseconds.");}) đưa ra CORS-Error: developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Lỗi / Lỗi Tôi không thấy cách tôi có thể kiểm tra mã này nếu một máy tính từ xa đang trực tuyến.
Thục

18

bạn có thể thử điều này:

đặt ping.html trên máy chủ có hoặc không có bất kỳ nội dung nào, trên javascript làm tương tự như dưới đây:

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

1
Các máy chủ tôi đang ping không phải của riêng tôi, vì vậy tôi không có tùy chọn đó. Cảm ơn mặc dù.
Chuck Callebs

9
@dlchambers Không phải tham gia CORS mà là DUE TO cross domain poilicy. CORS cho phép một máy chủ chỉ định nguồn gốc cộng với nó phải được trình duyệt hỗ trợ. vì vậy nó giống như một vấn đề tên miền chéo.
Royi Namir

Các yêu cầu loại CHÍNH sẽ không hoạt động vì CORS. Đã thử nghiệm với Chromium 55. Nhận được cùng một lỗi với mã http 0 như trong trường hợp net :: CONNMENT_REFUSED chẳng hạn.
Martin Vysny

Đây là nhiều trình duyệt chéo firendly.
Gabriel

14

Bạn không thể trực tiếp "ping" trong javascript. Có thể có một vài cách khác:

  • Ajax
  • Sử dụng một applet java với isReachable
  • Viết một kịch bản máy chủ sẽ ping và sử dụng AJAX để giao tiếp với máy chủ của bạn
  • Bạn cũng có thể ping trong flash (bản mô tả)

1
IsReachable của Java khá không đáng tin cậy .... Nhưng dù sao thì đó cũng là năm 2018 và các Applet Java đã lỗi thời.
dreua

8

Bạn không thể thực hiện ping thông thường trong Javascript trình duyệt, nhưng bạn có thể tìm hiểu xem máy chủ từ xa có còn sống hay không, ví dụ như tải hình ảnh từ máy chủ từ xa. Nếu tải không thành công -> máy chủ xuống.

Bạn thậm chí có thể tính toán thời gian tải bằng cách sử dụng sự kiện onload. Đây là một ví dụ về cách sử dụng sự kiện onload.


4
Điều đáng tiếc về điều đó là các máy chủ mà tôi đang sử dụng không phải là máy chủ web. Họ là những máy chủ trò chơi.
Chuck Callebs

1
Sau đó, bạn phải thực hiện ping trên phía máy chủ - hoặc bạn có thể xem xét một số máy chủ http nhẹ.
Epeli

Bạn có biết một cách để làm ping tổng hợp? Đó là sự chậm chạp chính của tôi, chờ đợi một yêu cầu kết thúc trước khi yêu cầu khác bắt đầu.
Chuck Callebs

Bạn cần ping máy chủ đồng thời. Bạn có thể đạt được điều đó với chọn, chủ đề hoặc quy trình. Đối với giải pháp thực sự khó khăn, bạn có thể sử dụng Eventmachine.
Epeli

1
Bạn có thể xem xét việc tận dụng lệnh dòng pinglệnh. Đó là sức mạnh công nghiệp. Hoặc, có tất cả các loại ứng dụng miễn phí / nguồn mở để theo dõi nếu máy chủ đang chạy, sử dụng nhiều loại kiểm tra nhịp tim khác nhau.
Tin Man

7

Tham gia giải pháp 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);
}

Không nên isUp();gọi trong onopenxử lý sự kiện? :)
jave.web

1
Nó sử dụng giao thức websocket nhưng giả sử thực tế không có máy chủ websocket đang chờ kết nối. Đây chỉ là để ping 'bất kỳ IP cũ'.
Rừng Antony

Nhưng làm thế nào bạn có thể phát hiện xem WebSocket chỉ không được hỗ trợ hay thực sự có một số lỗi? :)
jave.web

Nếu nghĩ rằng bạn sẽ không đủ may mắn để ping một IP có thể chấp nhận kết nối websocket trên cổng 80, thì có, bạn cũng nên thêm isUp();vào cuộc gọi lại đó. Hoặc giảm thiểu điều đó bằng cách thêm một cổng không phải websocket-y.
Rừng Antony

Tôi đã bỏ phiếu này vì tôi đến đây để tìm giải pháp cho những gì xảy ra khi máy chủ websocket của tôi được khởi động lại và câu trả lời này cho tôi thấy tôi có thể setTimeout trong trình xử lý lỗi của ổ cắm và cố gắng kết nối lại (chờ bận). Có lẽ không thực hành tốt nhất, nhưng giải quyết vấn đề của tôi. :)
mynameisnafe

6

Để giữ cho các yêu cầu của bạn nhanh chóng, hãy lưu trữ kết quả phía máy chủ của ping và cập nhật tệp ping hoặc cơ sở dữ liệu cứ sau vài phút (hoặc chính xác là bạn muốn nó). Bạn có thể sử dụng cron để chạy lệnh shell với 8 ping của mình và ghi đầu ra vào một tệp, máy chủ web sẽ đưa tệp này vào chế độ xem của bạn.


Tôi nghĩ rằng đây là cách đáng tin cậy nhất với kết quả chính xác nhất có thể. Tuy nhiên vì nó vẫn yêu cầu một số công việc trên máy chủ nên tôi sẽ nói đó không phải là cách thông minh.
Chetabahana

5

Nếu những gì bạn đang cố gắng xem là liệu máy chủ có "tồn tại" hay không, bạn có thể sử dụng như sau:

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

Điều này sẽ trả về một dấu hiệu đúng / sai cho dù máy chủ tồn tại.

Nếu bạn muốn thời gian phản hồi, một sửa đổi nhỏ sẽ làm:

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

Việc sử dụng là tầm thường:

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

Hoặc là:

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

Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
vonbrand

1
Đây là một giải pháp tuyệt vời, nhưng thật không may, dịch vụ truy vấn tên miền yahoo dường như cho kết quả khác nhau. ví dụ: nếu bạn thử các URL sau, hãy bắt đầu tải xuống .com bắt đầu tải xuống .com chúng quay lại dưới dạng chưa đăng ký, nhưng nếu bạn truy cập vào các URL đó, chúng rõ ràng đã được đăng ký. bất cứ ý tưởng những gì đang xảy ra ở đây? (tôi đã thêm một khoảng trắng cho các tên miền trong các ví dụ này, chỉ để tránh đưa ra nước trái cây google. Trong thử nghiệm của tôi, tôi không có khoảng
trắng

Bạn đang yêu cầu Yahoo! API, ping sẽ không giống nhau nếu bạn thực hiện một yêu cầu từ máy của mình. Điều này vô nghĩa
Andre Figueiredo

Nguyên nhân No 'Access-Control-Allow-Origin' header is present on the requested resource. Originvà gọi lại thành công này không bao giờ được gọi
vladkras

4

Vấn đề với ping tiêu chuẩn là ICMP, rất nhiều nơi không cho phép vì lý do an ninh và giao thông . Điều đó có thể giải thích cho sự thất bại.

Ruby trước 1.9 có dựa trên TCP ping.rb, sẽ chạy với Ruby 1.9+. Tất cả bạn phải làm là sao chép nó từ bản cài đặt 1.8.7 sang một nơi khác. Tôi chỉ xác nhận rằng nó sẽ chạy bằng cách ping bộ định tuyến nhà của tôi.


4

Có rất nhiều câu trả lời điên rồ ở đây và đặc biệt là về CORS -

Bạn có thể thực hiện một yêu cầu http CHÍNH (như GET nhưng không có tải trọng). Xem https://ochronus.com/http-head-request-good-uses/

Nó KHÔNG cần kiểm tra trước, sự nhầm lẫn là do phiên bản cũ của thông số kỹ thuật, xem Tại sao yêu cầu CHÍNH có nguồn gốc chéo cần kiểm tra trước?

Vì vậy, bạn có thể sử dụng câu trả lời ở trên đang sử dụng thư viện jQuery (không nói) nhưng với

type: 'HEAD'

--->

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

Dĩ nhiên bạn cũng có thể sử dụng vanilla js hoặc võ đường hoặc bất cứ điều gì ...


1
Gửi yêu cầu CHÍNH vẫn không thành công với "XMLHttpRequest không thể tải IP. Không có tiêu đề 'Access-Control-allow-Origin' trên tài nguyên được yêu cầu. Do đó, 'ip2' không được phép truy cập." Vì vậy, bị chặn bởi CORS. Bạn sẽ nhận được thành công với trạng thái http 0 và do đó bạn sẽ không thể phân biệt điều này với net :: ERR_CONNMENT_REFUSED chẳng hạn
Martin Vysny

0

Tôi không biết phiên bản Ruby nào bạn đang chạy, nhưng bạn đã thử triển khai ping cho ruby ​​thay vì javascript chưa? http://raa.ruby-lang.org/project/net-ping/


Vâng, tôi đã thử điều đó nhưng ping luôn trở lại sai, bất kể máy chủ web. Tôi đã thay đổi nó để chỉ sử dụng ping server.comcú pháp.
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)
});;

Nếu bạn chạy cái này với nút, nó sẽ điều khiển log 200 miễn là google không bị hỏng.


không, không phải ... 1) bạn đang thiếu yêu cầu, 2) nó sẽ quay trở lại 301 Đã di chuyển vĩnh viễn: 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);
    }
  });
};

sử dụng như thế này:

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

-4

Bạn có thể chạy lệnh DOS ping.exe từ javaScript bằng cách sử dụng 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;
}

Đây có phải là những gì đã được yêu cầu, hoặc tôi đang thiếu một cái gì đó?


4
Điều này sẽ chỉ hoạt động trên IE không may và chỉ trên Windows Server. Một lựa chọn tốt hơn sẽ là sử dụng AJAX để chạy tập lệnh phía máy chủ.
Andrew Grothe

Cái quái gì thế Các đối tượng Active X có thể thực thi trong hệ thống tệp của người dùng (trong IE trên máy chủ win) không? Tôi đã không làm việc với ActiveX nhưng không tưởng tượng được rằng ...
Julix


-8

Nó có thể dễ dàng hơn nhiều so với tất cả điều đó. Nếu bạn muốn trang của mình tải thì hãy kiểm tra tính khả dụng hoặc nội dung của một số trang nước ngoài để kích hoạt hoạt động của trang web khác, bạn có thể làm điều đó bằng cách chỉ sử dụng javascript và php như thế này.

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>

Nên làm vậy.

Các javascript được kích hoạt phải bao gồm ClearInterval (stopmelater)

Hãy cho tôi biết nếu điều đó làm việc cho bạn

Jerry


2
Như tôi đã nói trước đây, đây không phải là các máy chủ web. Đây là những máy chủ trò chơi. Họ sẽ không trả lời các yêu cầu HTTP. :(
Chuck Callebs 23/03 '

anh bạn, chỉ cần thay file_get_contents bằng
Jerry Wickey

$ ip = $ _SERVER ['127.0.0.1']; exec ("ping -n 4 $ ip 2> & 1", $ output, $ retval); if ($ retval! = 0) {echo "không!"; } khác {echo "có!"; }
Jerry Wickey

4
Đây không phải là một câu hỏi PHP. Đây là một câu hỏi JavaScript. Tôi không sử dụng PHP.
Chuck Callebs

1
Vui lòng không sử dụng chữ ký hoặc khẩu hiệu trong bài viết của bạn, nếu không chúng sẽ bị xóa. Xem FAQ để biết chi tiết.
Artemix

-13

Bạn có thể thử sử dụng PHP trong trang web của mình ... đại loại như thế này:

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

?>

Điều này không được kiểm tra nên nó có thể có lỗi chính tả, v.v ... nhưng tôi tin chắc rằng nó sẽ hoạt động. Cũng có thể được cải thiện ...


5
Theo các thẻ của OP, đây thực sự là một câu hỏi của Ruby on Rails, vì vậy sử dụng PHP không phải là một giải pháp tốt.
Tin Man

1
Không bắt đầu một cuộc tranh luận ở đây nhưng không phải là điểm của diễn đàn này để giúp đỡ?
Chris

5
@Chris Đó là, nhưng bạn đã giúp đỡ loại OP nào cho những người sử dụng Ruby và JS trong ứng dụng của mình bằng cách cung cấp mã PHP?
biphobe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.