Go to Contents Go to Java Page
J2SE 1.5 虎の穴
 
 

ついに Ping がうてるようになった InetAddress

 
 
Tiger

Ping だけが取り残されて...

 
 

リモートのマシンが正しく動いているか確かめるときに、ping はよく使われると思います。

ping は ICMP (Internet Control Message Protocol) というプロトコルを使用して行います。詳細は省略しますが、ICMP のエコーを使用して、マシンへの到達可能性 (Reachability) を確認するために使用されます。 詳しいことは RFC792 をご参照ください。

ICMP は TCP や UDP と同じように IP をベースにしているのですが、Tiger 以前では TCP や UDP は使えたのですが、ICMP だけは使うことができませんでした。

Tiger になってやっと ICMP が使えるようになりました。とはいっても実際に使えるのは Ping だけです。それもかなり機能は削られています。

というのも、ICMP で扱うタイプとコードの情報はまったく扱うことができずに、単にエコーに対する返信があったかどうかだけをチェックするものだからです。

それでも、ないよりましなので、さっそく使い方を調べてみましょう。

 

 
 
Tiger 使い方はとても簡単
 
 

使い方は簡単です。

サンプルのソース ReachabilityTest.java

このサンプルは Ping の動作をシミュレートするようなサンプルです。

さて、Reachability をチェックするには InetAddress#isReachable メソッドを使用します。このメソッドは引数によって 2 種類提供されています。一方が簡単なものでタイムアウトの時間だけを指定するもの。もう一方がネットワークインタフェース、TTL そしてタイムアウトを使用するものです。

通常はタイムアウトを指定するものだけで十分だと思います。

Reachability をチェックするには次のようにします。

    String addressText = ....
    InetAddress address = InetAddress.getByName(addressText);
 
    // Reachability のチェック ICMP が使用される
    boolean isReachable = address.isReachable(2000);

Socket クラスのようにポートを指定する必要はないので、InetSocketAddress クラスを使う必要はなく、InetAddress クラスを使用します。

また、Socket クラスとは異なり、プロトコルをハンドリングする必要もありません。単に isReachable メソッドをコールするだけです。

引数のタイムアウトはミリ秒なのですが、型は int です。通常、ミリ秒を表すときには long が使用されるので、ちょっとだけ注意が必要です。

戻り値は boolean なので、結果がタイムアウトなのか Unreachable なのかは判断できません。

サンプルの ReachabilityTest クラスでは開始時間と終了時間をチェックして、(終了時間 - 開始時間) がタイムアウト以上ならタイムアウトと判断しています。

ただ、Windows だとそのあたりをちゃんとハンドリングしていないみたいです。すべてタイムアウトになってしまいます。ちょっと if 文が深くなってしまって読みにくいかもしれませんが、サンプルで Reachability をチェックしている部分を載せておきます。

            long max = 0;
            long min = 0;
            long sum = 0;
            int num = 0;
 
            InetAddress address = InetAddress.getByName(addressText);
            System.out.println("Pinging " + address.getHostName() 
                               + " [" + address.getHostAddress() + "].\n");
 
            int i = 0;
            for (; i < 4; i++) {
                long start = System.currentTimeMillis();
 
                // Reachability のチェック ICMP が使用される
                boolean isReachable = address.isReachable(TIMEOUT);
                 
                long end = System.currentTimeMillis();
                long time = end - start;
 
                if (isReachable) {
                    System.out.print("Reply from " 
                                     + address.getHostAddress() + ": ");
 
                    sum += time;
 
                    if (i == 0) {
                        max = time;
                        min = time;
                    } else {
                        if (time > max) {
                            max = time;
                        } else if (time < min) {
                            min = time;
                        }
                    }
                    num++;
 
                    if (time > 0) {
                        System.out.println("time=" + time + "ms");
                    } else {
                        System.out.println("time<1ms");
                    }
                } else {
                    if (time >= TIMEOUT) {
                        System.out.println("Request timed out.");
                    } else {
                        System.out.println("Reply from " 
                                         + address.getHostAddress() 
                                         + ": Destination net unreachable.");
                        num++;
                    }
                }
 
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedExc???eption e) {
                    break;
                }
            }

コードは長いですが、実際の Reachability のチェックはたった 1 行。あとは経過時間や最大、最小時間などを調べています。

さて、これを実行してみましょう。まずはローカルホストから。

C:\examples>java ReachabilityTest localhost
Pinging localhost [127.0.0.1].

Reply from 127.0.0.1: time<1ms
Reply from 127.0.0.1: time<1ms
Reply from 127.0.0.1: time<1ms
Reply from 127.0.0.1: time<1ms

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
  
C:\examples>

同じように yahoo.com についてもやってみました。

C:\examples>java ReachabilityTest www.yahoo.com
Pinging www.yahoo.com [66.94.230.32].

Reply from 66.94.230.32: time=150ms
Reply from 66.94.230.32: time=160ms
Reply from 66.94.230.32: time=150ms
Reply from 66.94.230.32: time=150ms

Ping statistics for 66.94.230.32:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 150ms, Maximum = 160ms, Average = 152ms
  
C:\examples>

実際にはないマシンに対して行ってみます。10.0.0.1 はプライベートアドレスなので、公開されているものはないはずです。

C:\examples>java ReachabilityTest 10.0.0.1
Pinging 10.0.0.1 [10.0.0.1].

Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for 10.0.0.1:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
  
C:\examples>

すべてタイムアウトになりました。

私の使用している環境では IPv6 が使えないので、確かめることはできないのですが、IPv6 の ping6 も使用できるはずです。誰か確かめて、結果を教えてください。

 

 
 
Tiger おわりに
 
 

ICMP が使えなかったことよりは、1 歩前進して ping はうてるようになりました。しかし、エコーの戻りの解析はできません。でも、どこまでそれをやる必要があるかを考えると、なくてもいいのかもしれません。

ともあれ、できなかったことができるようになったので、よしとしましょう。

 

今回使用したサンプルはここからダウンロードできます。

 

参考

(Jun. 2004)

 
 
Go to Contents Go to Java Page