Javaを使用してネットワークの接続性をテストするいくつかの方法

17215 ワード

ネットワークプログラミングでは,2台の機器間の連通性,あるいは1台の機器から別の機器へのネットワーク達成性を判断する必要がある場合がある.システムレベルのテストでは、Pingコマンドを使用して検証することがよくあります.Javaは比較的豊富なネットワークプログラミングクラスライブラリを提供していますが(アプリケーション層でのURLベースのネットワークリソース読み取り、TCP/IP層ベースのSocketプログラミング、およびいくつかの補助的なクラスライブラリを含む)が、Pingコマンドのようなネットワーク接続性をテストする方法は直接提供されていない.Javaの既存のAPIを通じて、様々なシーンで2台の機器間のネットワーク達成性判断をプログラミングする方法について説明する.以下の章ではJavaネットワークでプログラミングされたクラスライブラリjavaを使用します.net.InetAddressとjava.net.Socketは、Pingコマンドをシミュレートする方法を例に説明します.
一般的には、1台のマシンから別のマシンにアクセスできるかどうかを判断する必要があります.この場合、Javaクラスライブラリのjava.net.InetAddressクラスを簡単に使用して実現できます.このクラスは、リモートマシンが到達できるかどうかを検出する2つの方法を提供します.

  
  
  
  
  1. boolean isReachable(int timeout) //
  2. boolean isReachable(NetworkInterface netif, int ttl, int timeout)
  3. // .

簡単に言えば、上記の方法は、リモートマシンのIPアドレスを介してInetAddressオブジェクトを構築し、そのisReachableメソッドを呼び出し、呼び出しマシンとリモートマシンのネットワーク達成性をテストすることである.リモートマシンに複数のIPアドレスがある可能性があるため、すべての状況を反復的にテストする可能性があることに注意してください.

  
  
  
  
  1. void isAddressAvailable(String ip){
  2. try{
  3. InetAddress address = InetAddress.getByName(ip);//ping this IP
  4. if(address instanceof java.net.Inet4Address){
  5. System.out.println(ip + " is ipv4 address");
  6. }else
  7. if(address instanceof java.net.Inet6Address){
  8. System.out.println(ip + " is ipv6 address");
  9. }else{
  10. System.out.println(ip + " is unrecongized");
  11. }
  12. if(address.isReachable(5000)){
  13. System.out.println("SUCCESS - ping " + IP + " with no interface specified");
  14. }else{
  15. System.out.println("FAILURE - ping " + IP + " with no interface specified");
  16. }
  17. System.out.println("
    -------Trying different interfaces--------
    "
    );
  18. Enumeration<NetworkInterface> netInterfaces =
  19. NetworkInterface.getNetworkInterfaces();
  20. while(netInterfaces.hasMoreElements()) {
  21. NetworkInterface ni = netInterfaces.nextElement();
  22. System.out.println(
  23. "Checking interface, DisplayName:" + ni.getDisplayName() + ", Name:" + ni.getName());
  24. if(address.isReachable(ni, 0, 5000)){
  25. System.out.println("SUCCESS - ping " + ip);
  26. }else{
  27. System.out.println("FAILURE - ping " + ip);
  28. }
  29. Enumeration<InetAddress> ips = ni.getInetAddresses();
  30. while(ips.hasMoreElements()) {
  31. System.out.println("IP: " + ips.nextElement().getHostAddress());
  32. }
  33. System.out.println("-------------------------------------------");
  34. }
  35. }catch(Exception e){
  36. System.out.println("error occurs.");
  37. e.printStackTrace();
  38. }
  39. }

プログラム出力:

  
  
  
  
  1. --------------START--------------
  2. 10.13.20.70 is ipv4 address
  3. SUCCESS - ping 10.13.20.70 with no interface specified
  4. -------Trying different interfaces--------
  5. Checking interface, DisplayName:MS TCP Loopback interface, Name:lo
  6. FAILURE - ping 10.13.20.70
  7. IP: 127.0.0.1
  8. -------------------------------------------
  9. Checking interface, DisplayName:Intel(R) Centrino(R) Advanced-N 6200 AGN -
  10. Teefer2 Miniport, Name:eth0
  11. FAILURE - ping 10.13.20.70
  12. IP: 9.123.231.40
  13. -------------------------------------------
  14. Checking interface, DisplayName:Intel(R) 82577LM Gigabit Network Connection -
  15. Teefer2 Miniport, Name:eth1
  16. SUCCESS - ping 10.13.20.70
  17. -------------------------------------------
  18. Checking interface, DisplayName:WAN (PPP/SLIP) Interface, Name:ppp0
  19. SUCCESS - ping 10.13.20.70
  20. IP: 10.0.50.189
  21. -------------------------------------------
  22. --------------END--------------

isReachableの使い方は、リモートネットワークの達成性を判断するためにインタフェースを指定しないことができますが、パケットがそのネットワークインタフェースから送信されたものであることを区別することはできません(ローカルに複数のネットワークインタフェースがある場合).一方、高度なバージョンのisReachableでは、ローカルのどのネットワークインタフェースからテストするかを指定できます.これにより、リモートネットワークがローカルのどのネットワークインタフェースに接続できるかを正確に知ることができます.
しかし、Java自体は、ローカルのどのIPアドレスがリモートネットワークに接続できるかを判断する方法を提供しておらず、JavaネットワークプログラミングインターフェースもICMPプロトコルパケットにアクセスする方法を提供していないため、ICMPのネットワークを介してパケットに到達できないことも不可能である(もちろんJNIで実現できるが、システムプラットフォームに関連している)、このとき,本稿の次節で提案する方法を考えることができる.
場合によっては、ローカルのどのネットワークアドレスがリモートネットワークに接続できるかを決定し、リモートネットワークがローカルに接続されて特定のサービスを使用したり、通知を発行したりすることができます.1つの典型的なアプリケーションシーンは、FTPのようなファイル転送サービスがローカルに開始され、リモートマシンがそのアドレスを通じてファイルをダウンロードできるように、ローカルのIPアドレスをリモートマシンに送信する必要がある.あるいは、リモートマシンは、いくつかのイベントが発生したときに、これらのイベントを取得したマシン(システム管理分野によく見られる)が登録されていることを通知するサービスを提供し、登録時にローカルの到達可能な(リモートから)アドレスを提供する必要がある.
私たちはInetAddressを使うことができますが.isReachabl法は,ローカルのどのネットワークインタフェースがリモートプレイに接続できるかを判断するが,単一のネットワークインタフェースは複数のIPアドレスを構成できるため,ここでは適切ではない.Socketを使用して可能なTCP接続を確立し、ローカルIPアドレスがリモートネットワークに達できるかどうかを判断することができます.javaを使います.net.ソケットクラスでの接続方法

  
  
  
  
  1. void connect(SocketAddress endpoint, int timeout) // Socket ,

この方法はリモートのポートが必要です.このポートは、TCPプロトコルに基づく任意のオープンサービスのポートであってもよい(例えば、一般にオープンであるECHOサービスポート7、LinuxのSSHサービスポート22等).実際には、確立されたTCP接続は、プロトコルスタックによって接続キューに配置され、実際にデータを処理する各アプリケーションサービスに配信されるが、UDPは接続プロセスがないため、UDPベースのサービスである(SNMPなど)この方法では適用できません.
具体的な手順は、ローカルの各ネットワークアドレスを列挙し、ローカルSocketを確立し、あるポートでリモートアドレスの接続を試み、接続可能であれば、そのローカルアドレスがリモートネットワークに達できることを示す.

  
  
  
  
  1. void printReachableIP(InetAddress remoteAddr, int port){
  2. String retIP = null;
  3. Enumeration<NetworkInterface> netInterfaces;
  4. try{
  5. netInterfaces = NetworkInterface.getNetworkInterfaces();
  6. while(netInterfaces.hasMoreElements()) {
  7. NetworkInterface ni = netInterfaces.nextElement();
  8. Enumeration<InetAddress> localAddrs = ni.getInetAddresses();
  9. while(localAddrs.hasMoreElements()){
  10. InetAddress localAddr = localAddrs.nextElement();
  11. if(isReachable(localAddr, remoteAddr, port, 5000)){
  12. retIP = localAddr.getHostAddress();
  13. break;
  14. }
  15. }
  16. }
  17. } catch(SocketException e) {
  18. System.out.println(
  19. "Error occurred while listing all the local network addresses.");
  20. }
  21. if(retIP == null){
  22. System.out.println("NULL reachable local IP is found!");
  23. }else{
  24. System.out.println("Reachable local IP is found, it is " + retIP);
  25. }
  26. }
  27. boolean isReachable(InetAddress localInetAddr, InetAddress remoteInetAddr,
  28. int port, int timeout) {
  29. booleanisReachable = false;
  30. Socket socket = null;
  31. try{
  32. socket = newSocket();
  33. // 0
  34. SocketAddress localSocketAddr = new InetSocketAddress(localInetAddr, 0);
  35. socket.bind(localSocketAddr);
  36. InetSocketAddress endpointSocketAddr =
  37. new InetSocketAddress(remoteInetAddr, port);
  38. socket.connect(endpointSocketAddr, timeout);
  39. System.out.println("SUCCESS - connection established! Local: " +
  40. localInetAddr.getHostAddress() + " remote: " +
  41. remoteInetAddr.getHostAddress() + " port" + port);
  42. isReachable = true;
  43. } catch(IOException e) {
  44. System.out.println("FAILRE - CAN not connect! Local: " +
  45. localInetAddr.getHostAddress() + " remote: " +
  46. remoteInetAddr.getHostAddress() + " port" + port);
  47. } finally{
  48. if(socket != null) {
  49. try{
  50. socket.close();
  51. } catch(IOException e) {
  52. System.out.println("Error occurred while closing socket..");
  53. }
  54. }
  55. }
  56. return isReachable;
  57. }

実行結果

  
  
  
  
  1. --------------START--------------
  2. FAILRE - CAN not connect! Local: 127.0.0.1 remote: 10.8.1.50 port22
  3. FAILRE - CAN not connect! Local: 9.123.231.40 remote: 10.8.1.50 port22
  4. SUCCESS - connection established! Local: 10.0.50.189 remote: 10.8.1.50 port22
  5. Reachable local IP is found, it is 10.0.50.189
  6. --------------END--------------

ネットワーク環境にIPv 4とIPv 6が存在する場合、すなわち、マシンにIPv 4アドレスとIPv 6アドレスがある場合、プログラムを最適化することができます.例えば、
  • IPv 4アドレスとIPv 6アドレスとの間では相互にアクセスできないため、IPv 4アドレスとIPv 6アドレスとの間の到達可能性のみを判断する必要がある.
  • IPv 4の転帰アドレスは判断せず、IPv 6のLinklocalアドレスはテスト
  • をスキップすることもできる.
  • 実際のニーズに応じて、IPv 4またはIPv 6の選択を優先的に考慮し、判断の効率を向上させることができる
  • .
    ローカルアドレスとリモートアドレスが同じIPv 4またはIPv 6であるかどうかを判断
    
      
      
      
      
    1. // IPv4 IPv6
    2. if(!((localInetAddr instanceofInet4Address) && (remoteInetAddr instanceofInet4Address)
    3. || (localInetAddr instanceofInet6Address) && (remoteInetAddr instanceofInet6Address))){
    4. // IPv4 IPv6, ,
    5. break;
    6. }

    ローカルアドレスとLinkLocalアドレスをスキップ
    
      
      
      
      
    1. if( localAddr.isLoopbackAddress() ||
    2. localAddr.isAnyLocalAddress() ||
    3. localAddr.isLinkLocalAddress() ){
    4. // ,
    5. break;
    6. }

    本稿では,集中的な典型的なシナリオを列挙し,Javaネットワークプログラミングインタフェースにより機器間の達成性を判断するいくつかの方式を紹介した.実際の応用では、必要に応じて適切な方法を選択して少し修正すればよい.より特殊なニーズに対しては、JNIの方法でシステムAPIを直接呼び出すことで実現することも考えられ、より強力で柔軟な機能を提供することができ、ここでは後述しない.
    記事の出典:http://www.ibm.com/developerworks/cn/java/j-lo-connectiontest/