91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP通過ICMP協議實現ping的示例分析

發布時間:2021-04-01 09:14:54 來源:億速云 閱讀:231 作者:小新 欄目:編程語言

小編給大家分享一下PHP通過ICMP協議實現ping的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

PHP通過ICMP協議實現ping(原始套接字)

最近想實現一個檢測目標主機是否在線的功能,用百度查了查,多是使用打開到某個端口的連接來判斷目標主機是否在線的。如Windows系統3389端口(RDP)和*nix系統的22端口(SSH)。

但這樣會出現一個問題,目標主機如果沒有開放這些端口,則會導致判斷上的錯誤。某個端口不開放并不代表目標主機離線。

由于大多數設備都會回應ping,由此想到了使用ping來實現這個功能。再次查詢百度,發現大多數教程都使用exec()函數調用系統ping命令來實現,這顯然很不安全。

所以最終決定使用PHP提供的原始套接字,自己構建ICMP包來實現ping。

要構建一個ICMP包,首先我們要了解ICMP包的結構。

PHP通過ICMP協議實現ping的示例分析

可以看到,一個標準的ICMP包由8位類型,8位代碼,16位校驗和,16位ID,16位序列號和數據組成。接下來,我們就通過PHP構建一個這樣的數據包。

$package = chr(8).chr(0);//模式 8 0
$package .= chr(0).chr(0);//置零校驗和
$package .= "R"."C";//ID 這里是我隨便填的
$package .= chr(0).chr(1);//序列號 一樣 隨便填的
for($i=strlen($package);$i<64;$i++){//填充滿64位
    $package .= chr(0);//數據
}

接下來計算校驗和。

$tmp = unpack("n*",$package);//把數據16位一組放進數組里
$sum = array_sum($tmp);//求和
$sum = ($sum >> 16) + ($sum & 0xFFFF);//結果右移十六位 加上結果與0xFFFF做AND運算
$sum = $sum + ($sum >> 16);//結果加上結果右移十六位
$sum = ~ $sum;//做NOT運算
$checksum = pack("n*", $sum);//打包成2字節

把校驗和填充進數據包。

$package[2] = $checksum[0];
$package[3] = $checksum[1];//填充校驗和

這樣,一個標準的ICMP數據包就構建好了,可以直接發送給目標主機了。Ready to go~

$host = "192.168.1.1";//設置目標主機
$socket=socket_create(AF_INET, SOCK_RAW, getprotobyname('icmp'));//創建原始套接字
$start = microtime();//記錄開始時間
socket_sendto($socket, $package, strlen($package), 0, $host, 0);//發送數據包
$read = array($socket);//初始化socket
$select = socket_select($read, $write, $except, 5);
if ($select === FALSE){
    $icmpError = "socket_select()方法發生錯誤,原因:".socket_strerror(socket_last_error());
    socket_close($socket);
}else if($select === 0){
    $icmpError = "請求超時";
    socket_close($socket);
}
if($icmpError !== NULL){
    echo $icmpError;
    exit();
}
socket_recvfrom($socket, $recv, 65535, 0, $host, $port);//接受回傳數據
/*回傳數據處理*/
$end = microtime();//記錄結束時間
$recv = unpack("C*", $recv);
$length = count($recv) - 20;//包長度 減去20字節IP報頭
$ttl = $recv[9];//ttl
$seq = $recv[28];//序列號
$duration = round(($end - $start) * 1000,3);//計算耗費的時間
echo "{$length} bytes from {$host}: icmp_seq={$seq}  ttl={$ttl} time={$duration}ms".PHP_EOL;//輸出結果

輕敲運行,一次ping請求就完成了。不出意外的話,結果應該如下顯示。

64 bytes from 192.168.1.1: icmp_seq=1  ttl=128 time=0.589ms

最后,我將這些代碼打包成了一個函數。把它加入你的代碼里,需要調用的時候,使用ping(string $host, int $retry)即可。

<?php
 function ping($host, $retry = 1){
    $g_icmp_error = NULL;
    $write = NULL;
    $except = NULL;//初始化所需變量
    $package = chr(8).chr(0);//模式 8 0
    $package .= chr(0).chr(0);//置零校驗和
    $package .= "R"."C";//ID
    $package .= chr(0).chr(1);//序列號
    for($i=strlen($package);$i<64;$i++){
        $package .= chr(0);
    }
    $tmp = unpack("n*",$package);//把數據16位一組放進數組里
    $sum = array_sum($tmp);//求和
    $sum = ($sum >> 16) + ($sum & 0xFFFF);//結果右移十六位 加上結果與0xFFFF做AND運算
    $sum = $sum + ($sum >> 16);//結果加上結果右移十六位
    $sum = ~ $sum;//做NOT運算
    $checksum = pack("n*", $sum);//打包成2字節
    $package[2] = $checksum[0];
    $package[3] = $checksum[1];//填充校驗和
    $socket=socket_create(AF_INET, SOCK_RAW, getprotobyname('icmp'));//創建原始套接字
    $start = microtime();//記錄開始時間
    socket_sendto($socket, $package, strlen($package), 0, $host, 0);//發送數據包
    $read = array($socket);//初始化socket
    $select = socket_select($read, $write, $except, 5);
    if ($select === FALSE){
        $icmpError = "socket_select()方法發生錯誤,原因:".socket_strerror(socket_last_error());
        socket_close($socket);
    }else if($select === 0){
        $icmpError = "請求超時";
        socket_close($socket);
    }
    if($icmpError !== NULL){
        echo $icmpError;
        exit();
    }
    socket_recvfrom($socket, $recv, 65535, 0, $host, $port);//接受回傳數據
    /*回傳數據處理*/
    $end = microtime();//記錄結束時間
    $recv = unpack("C*", $recv);
    $length = count($recv) - 20;//包長度 減去20字節IP報頭
    $ttl = $recv[9];//ttl
    $seq = $recv[28];//序列號
    $duration = round(($end - $start) * 1000,3);//計算耗費的時間
    echo "{$length} bytes from {$host}: icmp_seq={$seq}  ttl={$ttl} time={$duration}ms".PHP_EOL;//輸出結果
    
    socket_close($socket);//關閉socket
}
?>

文中如果有錯誤或不詳細的地方,歡迎在評論區指出和討論。

以上是“PHP通過ICMP協議實現ping的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

泰来县| 修水县| 金湖县| 连城县| 张掖市| 孟州市| 拜泉县| 原阳县| 柳江县| 安宁市| 思茅市| 六盘水市| 肇东市| 灵川县| 确山县| 湘乡市| 增城市| 平阴县| 博爱县| 吉林省| 山阴县| 称多县| 会理县| 北海市| 涿鹿县| 尼木县| 顺昌县| 桃园县| 广丰县| 施甸县| 灌南县| 冷水江市| 鹰潭市| 巧家县| 阜城县| 新泰市| 黎平县| 客服| 靖宇县| 民勤县| 永泰县|