public class NativeProcess { /** ping のタイムアウト(ms) */ private static String TIMEOUT = "3000"; public static void main(String... args) throws IOException, InterruptedException{ boolean ret = ping(Inet4Address.getByName("192.168.1.1")); System.out.println(ret ? "SUCCESS" : "FAILED"); } /** * Ping を実行し、ホストとの疎通を確認します。 * * @param target 疎通確認をしたいホスト * @return 疎通が確認できれば true, 確認できないなら false */ public static boolean ping(InetAddress target) throws IOException, InterruptedException{ // Windows の場合 String[] command = {"ping", "-n", "1", "-w", TIMEOUT, target.getHostAddress()}; // Linux の場合 // String[] command = {"ping", "-c", "1", "-t", TIMEOUT, target.getHostAddress()}; return new ProcessBuilder(command).start().waitFor() == 0; } }
Javaだけじゃできない
最初は、InetAddress#isReachable(int timeout)を使えばできると思ってました。
でも、コマンドプロンプトで ping が通るのが確認できているホストなのに、このメソッドだと false を返すという現象が発生しました。
おかしいと思ってAPIを読み返すと、以下のような記述が。
そのアドレスに到達可能かどうかをテストします。(中略)通常の実装では、特権を取得できる場合は ICMP ECHO REQUEST を使用し、それ以外の場合は接続先ホストのポート 7 (Echo) 上で TCP 接続を確立しようとします。
Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle
パケットアナライザーで確認したところ、どうやら ICMP ECHO REQUEST ではなく TCP ECHO が発信されている模様*1。
つまり、上記でいう「特権」とやらが取得できていない状態でした。
調べたら、ここでいう「特権」というのは Java の特権コードではなく、OSの特権(システムコール)のことのようです。
なんで、高々 ping で OS の特権なんて大げさな話になるのかと思ったら、ICMP パケットの送信/受信にはOSの特権(システムコール)が必要だ、とのこと。
How to do a true Java ping from Windows? - Stack Overflow
Mutant World: ICMP and InetAddress.isReachable()
そのため、Windows上や、Linux 上でも root 権限がないときには TCP ECHO で疎通確認をするみたいです。
でも、相手側が TCP ECHO の応答を返してくれるかどうかがあいまい*2なので、ping と同じ結果にはなりません。
なので、Javaだけじゃ無理。