`

使用Java测试网络连通性的几种方法

 
阅读更多

本文由浅入深地介绍了如何使用 Java 类库,判断两台机器之间网络是否可达。本文介绍了 Java 中三种不同的网络可达的判断方法以及针对 IPv4 和 IPv6 混合网络的编程方法。同时也介绍了这些方法的使用场景和优缺点,基本涵盖了在实际应用中可能碰到的各种情况。

AD:2013大数据全球技术峰会低价抢票中

在网络编程中,有时我们需要判断两台机器之间的连通性,或者说是一台机器到另一台机器的网络可达性。在系统层面的测试中,我们常常用 Ping 命令来做验证。尽管 Java 提供了比较丰富的网络编程类库(包括在应用层的基于 URL 的网络资源读取,基于 TCP/IP 层的 Socket 编程,以及一些辅助的类库),但是没有直接提供类似 Ping 命令来测试网络连通性的方法。本文将介绍如何通过 Java 已有的 API,编程实现各种场景下两台机器之间的网络可达性判断。在下面的章节中,我们会使用 Java 网络编程的一些类库 java.net.InetAddress 和 java.net.Socket,通过例子解释如何模拟 Ping 命令。

一般情况下,我们仅仅需要判断从一台机器是否可以访问(Ping)到另一台机器,此时,可以简单的使用 Java 类库中 java.net.InetAddress 类来实现,这个类提供了两个方法探测远程机器是否可达

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

程序输出:

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

从上可以看出 isReachable 的用法,可以不指定任何接口来判断远端网络的可达性,但这不能区分出数据包是从那个网络接口发出去的 ( 如果本地有多个网络接口的话 );而高级版本的 isReachable 则可以指定从本地的哪个网络接口测试,这样可以准确的知道远端网络可以连通本地的哪个网络接口。

但是,Java 本身没有提供任何方法来判断本地的哪个 IP 地址可以连通远端网络,Java 网络编程接口也没有提供方法来访问 ICMP 协议数据包,因而通过 ICMP 的网络不可达数据包实现这一点也是不可能的 ( 当然可以用 JNI 来实现,但就和系统平台相关了 ), 此时可以考虑本文下一节提出的方法。

在某些情况下,我们可能要确定本地的哪个网络地址可以连通远程网络,以便远程网络可以回连到本地使用某些服务或发出某些通知。一个典型的应用场景 是,本地启动了文件传输服务 ( 如 FTP),需要将本地的某个 IP 地址发送到远端机器,以便远端机器可以通过该地址下载文件;或者远端机器提供某些服务,在某些事件发生时通知注册了获取这些事件的机器 ( 常见于系统管理领域 ),因而在注册时需要提供本地的某个可达 ( 从远端 ) 地址。

虽然我们可以用 InetAddress.isReachabl 方法判断出本地的哪个网络接口可连通远程玩过,但是由于单个网络接口是可以配置多个 IP 地址的,因而在此并不合适。我们可以使用 Socket 建立可能的 TCP 连接,进而判断某个本地 IP 地址是否可达远程网络。我们使用 java.net.Socket 类中的 connect 方法

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

运行结果

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

当网络环境中存在 IPv4 和 IPv6,即机器既有 IPv4 地址,又有 IPv6 地址的时候,我们可以对程序进行一些优化,比如

  • 由于 IPv4 和 IPv6 地址之间是无法互相访问的,因此仅需要判断 IPv4 地址之间和 IPv6 地址之间的可达性。
  • 对于 IPv4 的换回地址可以不做判断,对于 IPv6 的 Linklocal 地址也可以跳过测试
  • 根据实际的需要,我们可以优先考虑选择使用 IPv4 或者 IPv6,提高判断的效率

判断本地地址和远程地址是否同为 IPv4 或者 IPv6 

  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/

分享到:
评论

相关推荐

    Java代码测试IP是否为真实IP

    对于测试IP是否可达的功能,可以模拟不同网络条件,如连通的IP、不可达的IP、无效的IP,验证`isReachable()`方法的行为。 通过以上步骤,我们可以构建一个完整的Java工程,实现对IP地址的真实性和可达性的测试。在...

    java PING的综合测试

    在IT行业中,网络通信是至关重要的一个环节,而`PING`命令作为一种基本的网络诊断工具,被广泛用于检查网络连通性、测量网络延迟以及评估网络的稳定性。本篇文章将详细探讨`Java`中实现`PING`的综合测试,包括最大...

    编程实现基于UDP的PING (Java)

    在计算机网络中,PING是一种广泛使用的诊断工具,用于测试网络连通性和测量数据包往返时间。通常,PING基于ICMP(Internet Control Message Protocol)协议,但在这个特定的课程设计中,我们将关注如何使用UDP(User...

    GN算法的java实现

    通过迭代移除具有最高边缘间介数的边,网络会逐渐分裂成多个社团,每个社团内的节点连通性强,社团间的连通性弱。 Java作为一种广泛应用的编程语言,被用来实现GN算法是因为其强大的面向对象特性、丰富的库支持以及...

    udp_Ping_JAVAping_javaudpping_java_基于UDP的PING_udp_Ping_

    UDP_Ping是利用UDP协议实现的一种类似TCP/IP中的Ping工具,用于测试网络连通性和测量数据传输延迟。 在Java中实现UDP_Ping,主要涉及以下几个核心概念和技术: 1. **DatagramSocket**:Java中的`java.net....

    gn算法的java实现

    如果移除某条边会导致更多的不连通组件,那么这条边的模割值就高,表示它在维护网络连通性上扮演着关键角色。 3. **社区检测**:目标是将网络中的节点划分为若干个社区,使得每个社区内的节点相互紧密连接,而社区...

    12306验证码JAVA DEMO

    12306验证码JAVA DEMO是一个典型的计算机编程示例,主要关注的是使用Java语言来实现对12306网站验证码的识别和处理。在12306购票系统中,验证码是为了防止恶意机器人自动刷票而设置的一种安全机制。它的设计通常包括...

    基于Java的实例源码-第三代的P2P网络 ANts P2P.zip

    节点间的连接管理和维护是通过节点发现和保持连通性协议实现的,这在源码中表现为网络层的实现。 2. **路由算法**:ANts P2P采用Kademlia DHT(分布式哈希表)算法来实现高效的路由策略。这种算法基于节点ID的位...

    网络判断,界面启动

    网络判断的方法多种多样,常见的有以下几种: 1. **检查网络连接状态**:通过Android的`ConnectivityManager`类获取网络连接的状态,例如`NetworkInfo`对象的`isConnected()`方法。在Java中,可以使用`java.net....

    java验证码识别 自娱自乐

    验证码识别在IT行业中是一项重要的技术,特别是在网络安全和自动化测试领域。这个Java项目专注于实现验证码的自动识别,让我们深入了解其中涉及的知识点。 首先,验证码(CAPTCHA)是“Completely Automated Public...

    NOKIA手机软件测试

    8. 数据连通:测试蓝牙、Wi-Fi、USB数据传输、网络浏览等,确保数据交换的稳定性。 9. JAVA程序:验证J2ME应用程序的运行、安装和卸载,以及与系统资源的交互。 再者,了解手机的软件和硬件结构对测试至关重要: 1...

    Java数据结构和算法中文第二版(1)

    几种简单排序之间的比较 小结 问题 实验 编程作业 第4章 栈和队列 不同的结构类型 栈 队列 优先级队列 解析算术表达式 小结 问题 实验 编程作业 第5章 链表 链结点(Link) LinkList专题Applet...

    20151910042-刘鹏-CN实验01-计算机网络平台预备实验1

    2. **测试连通性**:使用`ping 127.0.0.1`命令检查本地环回接口的连通性。127.0.0.1是回送地址,用于测试本机的网络栈是否正常工作。若能成功ping通,表示网络栈运行良好。 3. **建立主要网络服务**:了解并设置...

    machine-learning-in-java-master.zip_java_java手写识别_machine learni

    本项目“machine-learning-in-java-master”即为一个用Java语言实现的数字手写识别系统,它将传统的图像处理技术与现代的机器学习算法相结合,为用户提供了一种高效且灵活的解决方案。 首先,让我们了解手写数字...

    TCP测试工具

    这有助于检查网络连通性、端口是否开放等问题。 2. **断开连接**:测试工具应能模拟连接关闭,验证TCP四次挥手(FIN-ACK-FIN-ACK)过程,确保连接被正确释放,没有资源泄漏。 3. **数据传输**:工具应能发送各种...

    WLAN网络监控系统使用维护手册宣贯.pdf

    ping命令通过发送ICMP回显请求消息到目标主机并接收回应,来测试两台主机之间的连通性。 #### Telnet Telnet是一种网络协议,用于通过终端仿真进行远程登录。但在现代网络管理中,由于其不安全性,已越来越多地被...

    借助Sigar API获取网络信息

    Sigar(System Information Gatherer and Reporter)是一款强大的跨平台系统信息收集库,它提供了一种简单的方法来获取操作系统级别的信息,包括但不限于网络状态、进程信息、内存使用情况、磁盘统计等。在Java环境...

    Java做的无色连珠游戏

    游戏采用了“广度搜索”作为其关键算法之一,这是一种在图或树中寻找路径的常用方法,它从起始节点开始,逐层遍历所有相邻节点,直到找到目标节点或者遍历完所有节点。在无色连珠游戏中,广度搜索可能用于识别并消除...

Global site tag (gtag.js) - Google Analytics