3

私はサーバー用の非常にシンプルな稼働時間モニターを作成しました(他の人のコードからうまくまとめました)-それは単なるICMP(ping)モニターであり、限られた数のサーバー(20程度)で非常にうまく機能し、非常に高速です。これがコードです(実際のpingテスト関数はBirk Jensenの作業( http://birk-jensen.dk/2010/09/php-ping/ )に基づいていると思います)。彼の関数を使用して緑色を表示しました。すべてが稼働している場合はPNGを丸で囲み、停止しているサーバーごとに赤い丸を付けます(存在する場合)。

<html>
<head>
<style type='text/css'>

*{
    font-family:verdana,tahoma,arial;
    font-size:17px;
}

.light{width:30px;}

h1{
        font-size:25px;
}
</style>



<meta http-equiv="refresh" content="30">
</head>
<body>
<?php

$time1=date('H:i:s');
echo "Last Refresh Time = $time1<br/><hr/>";

error_reporting(0);

/*-----------------------------------------------------------------------------------------*/    
    // Checksum calculation function
    function icmpChecksum($data)
    {
    if (strlen($data)%2)
    $data .= "\x00";

    $bit = unpack('n*', $data);
    $sum = array_sum($bit);

    while ($sum >> 16)
    $sum = ($sum >> 16) + ($sum & 0xffff);

    return pack('n*', ~$sum);
    }


/*-----------------------------------------------------------------------------------------*/
    function PingTry1($pingaddress){
    // Making the package
    $type= "\x08";
    $code= "\x00";
    $checksum= "\x00\x00";
    $identifier = "\x00\x00";
    $seqNumber = "\x00\x00";
    $data= "testing123";
    $package = $type.$code.$checksum.$identifier.$seqNumber.$data;
    $checksum = icmpChecksum($package); // Calculate the checksum
    $package = $type.$code.$checksum.$identifier.$seqNumber.$data;
    // And off to the sockets
    $socket = socket_create(AF_INET, SOCK_RAW, 1);

    socket_set_option ( $socket, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>1, "usec"=>0) );
    socket_connect($socket, $pingaddress, null);

    $startTime = microtime(true);
    socket_send($socket, $package, strLen($package), 0);
    if (socket_read($socket, 255)) {
    return true;
    }
    else{
    return false;
    }

    socket_close($socket);

    }
/*-----------------------------------------------------------------------------------------*/
   function DoTheCheck($name,$ip){
       global $errors;
       global $j;
       if (PingTry1($ip)==1){
    //do nothing
                      }else{
                      $j++;
                      $errors[$j] = "$name --> $ip";

                      }

    }
/*-----------------------------------------------------------------------------------------*/

//READ IN THE INI FILE INTO $filedata Array

$myFile1="hosts.ini";
$filehandle1 = fopen($myFile1, 'r') or die("Couldn't open file [$myFile1]");
$number1=count(file($myFile1));;
$filedata = fread($filehandle1, filesize($myFile1));
fclose($filehandle1);

// Create an array with each line of the file
$array1 = explode("\r\n", $filedata);

unset($filedata); //free up a bit of memory

foreach ($array1 as &$line) { // step through the array, line by line
    if (!empty($line)){
list ($name,$ip)=split(",",$line);
    DoTheCheck($name,$ip);
                 }
}


    if ($errors){

            echo 'The Following Hosts are down - <br/><br/><table>';

foreach ($errors as &$value) {
    $k++;
    echo '<tr><td><img class="light" src="red.png" /></td><td>'.$errors[$k].'</td></tr>';
}
echo '</tr></table>';
    }
else{echo '<img class="light" src="green.png" /><h1>ALL IPS ARE UP!</h1>';}




    ?>
    </body>
    </html>

上記のコードはサーバーではうまく機能しますが、Ciscoスイッチではまったく機能しないようです。おそらく、「ping」自体の実行方法と関係があります。

私は大学の取り組みなどのためにこのスクリプトの作業を何年も行っていませんが、できる限り多くのグーグル調査を行うことに戻りましたが、確かに私はせいぜいレベル2または3のPHPn00bです。今日、スイッチで機能するソリューションをいくつか見つけましたが、5秒または6秒のタイムアウト期間があります。これは、システムを可能な限りクリーンにループさせ、後でグラフ化するためにダウンタイムをログに記録するため、許容できません。

例-私はこれを試しました:

   function ping($host, $timeout = 1) {
                /* ICMP ping packet with a pre-calculated checksum */
                $package = "\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost";
                $socket  = socket_create(AF_INET, SOCK_RAW, 1);
                socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
                socket_connect($socket, $host, null);

                $ts = microtime(true);
                socket_send($socket, $package, strLen($package), 0);
                if (socket_read($socket, 255))
                        $result = microtime(true) - $ts;
                else    $result = false;
                socket_close($socket);

                return $result;
        }

そしてこれも:

    $url         = '192.168.1.1'; 
    $socket       = ( bool )false; 
    $error      = ( bool )false; 

    $socket = @fsockopen( $url, 23, $errno, $errstr, 1 ) or $error = ( bool )true; 

    if ( ( $socket ) && ( !$error ) ) 
    { 
        echo "bound";
        /* socket is bound - do something */ 
    } 
    else 
    { 
        echo "not bound , [$errstr]";
        /* socket is dead - errors are in $errno & $errstr */ 
    }  

if ($socket)fclose($socket);

そして、どちらもホストがオンラインのときに機能するように見えますが、存在しないIPを指定すると(テストのために、ホストがオフラインであるかのように)、単一のIPでタイムアウトするのに約5秒以上かかります。これは私のニーズには遅すぎます。

pcntl_forkを使用してこれを行うことは可能ですか、それともマルチスレッドでcurlを使用することもできますか?または複数の「exec」呼び出しまたはAJAXも(この段階で何でも試してみます)

または、ある種のデータレイヤー(レイヤー2)のMacスキャンコードも素晴らしいでしょう-誰もが完全なコードを書くことは期待していませんが、以前にこの種のことをしたことがある人は、落とし穴とその回避方法。

要約すると、シンプルで簡単な修正があればいいのですが(私は夢を見続けます:-D)、どんな助けやアドバイスも大歓迎です。

編集-PEARでNet_Pingを試すためのアドバイスの後、次のコードがあります。

<?php

$time1=date('H:i:s');
echo "Last Refresh Time = $time1<br/><hr/>";

//not sure if still needed -       error_reporting(0);


require_once "Net/Ping.php";
$ping = Net_Ping::factory();

$ping->setArgs(array('count' => 2, 'ttl' => 50, 'timeout' => 1));
/*---------------------------------------------------------------------*/
function DoPing($ip)
{
    global $ping;

    $results = $ping->ping($ip);
    if ($results->_loss==0) {return true;}else{return false;}
}
/*---------------------------------------------------------------------------------*/
   function DoTheCheck($name,$ip){
       global $errors;
       global $j;

       if (DoPing($ip)==1){
    //do nothing
                      }else{
                      $j++;
                      $errors[$j] = "$name --> $ip";
                      }
    }
/*-----------------------------------------------------------------------------------*/

//READ IN THE INI FILE INTO $filedata Array

$myFile1="hosts.ini";
$filehandle1 = fopen($myFile1, 'r') or die("Couldn't open file [$myFile1]");
$number1=count(file($myFile1));;
$filedata = fread($filehandle1, filesize($myFile1));
fclose($filehandle1);

// Create an array with each line of the file
$array1 = explode("\r\n", $filedata);

unset($filedata); //free up a bit of memory

foreach ($array1 as &$line) { // step through the array, line by line
    if (  (!empty($line)) && (!strstr($line,'##'))  ) {
list ($name,$ip)=split(",",$line);
    DoTheCheck($name,$ip);
                 }
}

    if ($errors){

            echo 'The Following Hosts are down - <br/><br/><table>';

foreach ($errors as &$value) {
    $k++;
    echo '<tr><td><img class="light" src="red.png" /></td><td>'.$errors[$k].'</td></tr>';
}
echo '</tr></table>';
    }
else{echo '<img class="light" src="green.png" /><h1>ALL IPS ARE UP!</h1>';}

?>

しかし、それは遅すぎます...約20台のサーバーと10台のスイッチをチェックするのに約1〜2分かかります。遅くなるだけなので、約100個のスイッチを追加する必要があります。これを行うためのより良い方法があるはずです。繰り返しになりますが、どんな助けでも常に非常に高く評価されています。おそらくMuninを試してみますが、現実的には、会社のイントラネット(PHP)に統合できるものが必要です。

4

1 に答える 1

1

Muninのような適切な監視システムをもう試しましたか?手作りのスクリプトとは対照的に、動作することが知られています。インターネット接続を監視し、サーバーが利用可能かどうかを監視するために使用します。そのためのpingプラグインを提供します。Muninは、エラーが発生した場合にもメールを送信し、優れたグラフを描画します。

NagiosとCactiもありますが、Muninが最も簡単にセットアップできることがわかりました。

本当に本当にPHPだけを使い続けたい場合は、pingを送信するためのAPIを提供するPEARのNet_Pingパッケージをご覧ください。

編集:スピード

すべてのホストに次々にpingを実行するのは遅すぎるため、pingを並列化する必要があります。Net_Pingはこれをサポートしていないため、複数のPHPプロセスを並行して実行する必要があります。PHPのpcntl関数または関数の1つを使用しshell_execます。pingスクリプトは、コマンドラインパラメーターとしてのみホストにpingを提供し、pingの結果を共有ログファイルに記録します。メインスクリプトは、すべてのpingスクリプトが終了するまで待機し、ログに記録された情報を収集します。

于 2011-06-01T08:27:21.140 に答える