问题描述
||
我已经为我们的服务器编写了一个非常简单的正常运行时间监控器(与其他人的代码紧密结合在一起),它只是一个ICMP(ping)监控器,它对于我们数量有限的服务器非常有效(20左右),而且速度非常快。
这是代码(我认为实际的ping测试功能是基于Birk Jensen的工作(http://birk-jensen.dk/2010/09/php-ping/),而我只是利用其功能在一切正常时显示绿色圆圈PNG,而在每台故障的服务器上显示红色圆圈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级PHP n00b。
今天,我发现了一些适用于交换机的解决方案,但是它们有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,1);
socket_set_option($socket,array(\'sec\' => $timeout,\'usec\' => 0));
socket_connect($socket,$host,null);
$ts = microtime(true);
socket_send($socket,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甚至使用多线程进行卷曲?或多个\'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,line by line
if ( (!empty($line)) && (!strstr($line,\'##\')) ) {
list ($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台交换机。我需要添加大约100个开关,因此只会变慢。必须有更好的方法来做到这一点。同样,任何帮助总是非常感激。我可能会尝试Munin,但实际上我需要可以集成到公司的Intranet(PHP)中的东西。
解决方法
您是否尝试过像Munin这样的适当监视系统?与您手工制作的脚本相反,它可以工作。我用它来监视我的互联网连接以及服务器是否可用;它为此提供了一个ping插件。 Munin还会发送邮件以防出错,并绘制漂亮的图形。
也有Nagios和Cacti,但我发现Munin最容易设置。
如果您真的真的想单独使用PHP,请查看PEAR的Net_Ping软件包,该软件包提供了用于发送ping的API。
编辑:速度
由于一次又一次地对所有主机执行ping操作太慢,因此您需要并行执行ping操作。 Net_Ping不支持此功能,因此您必须并行运行多个PHP进程。使用PHP的pcntl函数或
shell_exec
函数之一。
可以仅将ping脚本作为主机的ping参数仅授予主机ping,并将ping结果记录在共享日志文件中。主脚本会一直等到所有ping脚本结束并收集记录的信息。