潭州学院教你使用java测试网络连通性在网络编程中,有时我们需要判断两台机器之间的连通性,或者说是一台机器到另一台机器的网络可达性。在系统层面的测试中,我们常常用Ping命令来做验证。尽管Java提供了比较丰富的网络编程类库(包括在应用层的基于URL的网络资源读取,基于TCP/IP层的Socket编程,以及一些辅助的类库),但是没有直接提供类似Ping命令来测试网络连通性的方法。本文将介绍如何通过Java已有的API,编程实现各种场景下两台机器之间的网络可达性判断。在下面的章节中,我们会使用Java网络编程的一些类库java.net.InetAddress和java.net.Socket,通过例子解释如何模拟Ping命令。一般情况下,我们仅仅需要判断从一台机器是否可以访问(Ping)到另一台机器,此时,可以简单的使用Java类库中java.net.InetAddress类来实现,这个类提供了两个方法探测远程机器是否可达booleanisReachable(inttimeout)//测试地址是否可达booleanisReachable(NetworkInterfacenetif,intttl,inttimeout)//测试地址是否可达.简单说来,上述方法就是通过远端机器的IP地址构造InetAddress对象,然后调用其isReachable方法,测试调用机器和远端机器的网络可达性。注意到远端机器可能有多个IP地址,因而可能要迭代的测试所有的情况。voidisAddressAvailable(Stringip){try{InetAddressaddress=InetAddress.getByName(ip);//pingthisIPif(addressinstanceofjava.net.Inet4Address){System.out.println(ip+isipv4address);}elseif(addressinstanceofjava.net.Inet6Address){System.out.println(ip+isipv6address);}else{System.out.println(ip+isunrecongized);}if(address.isReachable(5000)){System.out.println(SUCCESS-ping+IP+withnointerfacespecified);}else{System.out.println(FAILURE-ping+IP+withnointerfacespecified);}System.out.println(\n-------Tryingdifferentinterfaces--------\n);EnumerationNetworkInterfacenetInterfaces=NetworkInterface.getNetworkInterfaces();while(netInterfaces.hasMoreElements()){NetworkInterfaceni=netInterfaces.nextElement();System.out.println(Checkinginterface,DisplayName:+ni.getDisplayName()+,Name:+ni.getName());if(address.isReachable(ni,0,5000)){System.out.println(SUCCESS-ping+ip);}else{System.out.println(FAILURE-ping+ip);}EnumerationInetAddressips=ni.getInetAddresses();while(ips.hasMoreElements()){System.out.println(IP:+ips.nextElement().getHostAddress());}System.out.println(-------------------------------------------);}}catch(Exceptione){System.out.println(erroroccurs.);e.printStackTrace();}}程序输出:--------------START--------------10.13.20.70isipv4addressSUCCESS-ping10.13.20.70withnointerfacespecified-------Tryingdifferentinterfaces--------Checkinginterface,DisplayName:MSTCPLoopbackinterface,Name:loFAILURE-ping10.13.20.70IP:127.0.0.1-------------------------------------------Checkinginterface,DisplayName:Intel(R)Centrino(R)Advanced-N6200AGN-Teefer2Miniport,Name:eth0FAILURE-ping10.13.20.70IP:9.123.231.40-------------------------------------------Checkinginterface,DisplayName:Intel(R)82577LMGigabitNetworkConnection-Teefer2Miniport,Name:eth1SUCCESS-ping10.13.20.70-------------------------------------------Checkinginterface,DisplayName:WAN(PPP/SLIP)Interface,Name:ppp0SUCCESS-ping10.13.20.70IP:10.0.50.189---------------------------------------------------------END--------------从上可以看出isReachable的用法,可以不指定任何接口来判断远端网络的可达性,但这不能区分出数据包是从那个网络接口发出去的(如果本地有多个网络接口的话);而高级版本的isReachable则可以指定从本地的哪个网络接口测试,这样可以准确的知道远端网络可以连通本地的哪个网络接口。但是,Java本身没有提供任何方法来判断本地的哪个IP地址可以连通远端网络,Java网络编程接口也没有提供方法来访问ICMP协议数据包,因而通过ICMP的网络不可达数据包实现这一点也是不可能的(当然可以用JNI来实现,但就和系统平台相关了),此时可以考虑本文下一节提出的方法。在某些情况下,我们可能要确定本地的哪个网络地址可以连通远程网络,以便远程网络可以回连到本地使用某些服务或发出某些通知。一个典型的应用场景是,本地启动了文件传输服务(如FTP),需要将本地的某个IP地址发送到远端机器,以便远端机器可以通过该地址下载文件;或者远端机器提供某些服务,在某些事件发生时通知注册了获取这些事件的机器(常见于系统管理领域),因而在注册时需要提供本地的某个可达(从远端)地址。虽然我们可以用InetAddress.isReachabl方法判断出本地的哪个网络接口可连通远程玩过,但是由于单个网络接口是可以配置多个IP地址的,因而在此并不合适。我们可以使用Socket建立可能的TCP连接,进而判断某个本地IP地址是否可达远程网络。我们使用java.net.Socket类中的connect方法voidconnect(SocketAddressendpoint,inttimeout)//使用Socket连接服务器,指定超时的时间这种方法需要远程的某个端口,该端口可以是任何基于TCP协议的开放服务的端口(如一般都会开放的ECHO服务端口7,Linux的SSH服务端口22等)。实际上,建立的TCP连接被协议栈放置在连接队列,进而分发到真正处理数据的各个应用服务,由于UDP没有连接的过程,因而基于UDP的服务(如SNMP)无法在此方法中应用。具体过程是,枚举本地的每个网络地址,建立本地Socket,在某个端口上尝试连接远程地址,如果可以连接上,则说明该本地地址可达远程网络。voidprintReachableIP(InetAddressremoteAddr,intport){StringretIP=null;EnumerationNetworkInterfacenetInterfaces;try{etInterfaces=NetworkInterface.getNetworkInterfaces();while(netInterfaces.hasMoreElements()){NetworkInterfaceni=netInterfaces.nextElement();EnumerationInetAddresslocalAddrs=ni.getInetAddresses();while(localAddrs.hasMoreElements()){InetAddresslocalAddr=localAddrs.nextElement();if(isReachable(localAddr,remoteAddr,port,5000)){retIP=localAddr.getHostAddress();break;}}}}catch(SocketExceptione){System.out.println(Erroroccurredwhilelistingallthelocalnetworkaddresses.);}if(retIP==null){System.out.println(NULLreachablelocalIPisfound!);}else{System.out.println(ReachablelocalIPisfound,itis+retIP);}}booleanisReachable(InetAddresslocalInetAddr,InetAddressremoteInetAddr,intport,inttimeout){booleanisReachable=false;Socketsocket=null;try{socket=newSocket();//端口号设置为0表示在本地挑选一个可用端口进行连接SocketAddresslocalSocketAddr=newInetSocketAddress(localInetAddr,0);socket.bind(localSocketAddr);InetSocketAddressendpointSocketAddr=ewInetSocketAddress(remoteInetAddr,port);socket.connect(endpointSocketAddr,timeout);System.out.println(SUCCESS-connectionestablished!Local:+localInetAddr.getHostAddress()+remote:+remoteInetAddr.getHostAddress()+port+port);isReachable=true;}catch(IOExceptione){System.out.println(FAILRE-CANnotconnect!Local:+localInetAddr.getHostAddress()+remote:+remoteInetAddr.getHostAddress()+port+port);}finally{if(socket!=null){try{socket.cl