Windows環境でpingを打つときに気をつけるべきこと

業務系のシステムだと、pingで疎通確認はよくあるシーンだと思いますが、先日ハマったところがあったのでメモしておきたいと思います。

今回はphpで書いています。
よくあるpingコマンド送信例が以下。

function ping($host){
  exec(sprintf('ping -n 1 -w 1500 %s', escapeshellarg($host)), $output, $status);
  return $status === 0;
}
if(ping("192.168.10.100")){
  var_dump("ping OK!");
}else{
  var_dump("ping NG...");
}

Linux環境ならおそらくこれで問題ないのですが(注)、Windows環境だと問題が発生する($statusが0になる)ケースがあります。
上記の関数中、$outputの内容をvar_dumpで見てみるとわかります。

pingが通ったケース

array(8) {
 [0]=> string(0) ""
 [1]=> string(53) "127.0.0.1 に ping を送信しています 32 バイトのデータ:"
 [2]=> string(52) "127.0.0.1 からの応答: バイト数 =32 時間 <1ms TTL=128"
 [3]=> string(0) ""
 [4]=> string(23) "127.0.0.1 の ping 統計:"
 [5]=> string(58) " パケット数: 送信 = 1、受信 = 1、損失 = 0 (0% の損失)、"
 [6]=> string(37) "ラウンド トリップの概算時間 (ミリ秒):"
 [7]=> string(38) " 最小 = 0ms、最大 = 0ms、平均 = 0ms"
}

pingが通らなかったケース

array(6) {
 [0]=> string(0) ""
 [1]=> string(57) "192.168.10.100 に ping を送信しています 32 バイトのデータ:"
 [2]=> string(28) "要求がタイムアウトしました。"
 [3]=> string(0) ""
 [4]=> string(27) "192.168.10.100 の ping 統計:"
 [5]=> string(60) " パケット数: 送信 = 1、受信 = 0、損失 = 1 (100% の損失)、"
}

pingが通らなかったのに通ってしまうケース

array(6) {
 [0]=> string(0) ""
 [1]=> string(57) "192.168.10.100 に ping を送信しています 32 バイトのデータ:"
 [2]=> string(55) "192.168.10.1 からの応答: 宛先ホストに到達できません。"
 [3]=> string(0) ""
 [4]=> string(27) "192.168.10.100 の ping 統計:"
 [5]=> string(58) " パケット数: 送信 = 1、受信 = 1、損失 = 0 (0% の損失)、"
}

これは、ゲートウェイからの「到達できない」という応答が正常な終了として判断され、コマンドのステータス($status)が0(正常に終了)と返されるのが原因です。
これには本当にハマりました…

解決として、配列$outputのキー[6]が存在するかどうかで判定してみましたが、かなり苦し紛れです…
fsocketopenを使った死活監視を案内しているページもありますが、ポートを指定したくない状況では解決になりません。
正しい解決方法をご存知の方がいらっしゃいましたらぜひご教示いただけると幸いです…


軽く調べてみましたが、Linux環境ではゲートウェイから応答する挙動が確認できませんでした。
しかしながら、詳細に確認していませんので、本当に問題がないかどうかはご自身で確認してください。

2週間前