下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

如何使用Java测试网络连通性(2)

作者:课课家教育     来源: http://www.kokojia.com点击数:1211发布时间: 2016-02-03 14:19:43

标签: java程序javajava入门

大神带你学编程,欢迎选课

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

如何使用Java测试网络连通性(2)_java程序_java课程标准_课课家

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

  指定本地和远程网络地址,判断两台机器之间的 可达性

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

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

  这种方法需要远程的某个端口,该端口可以是任何基于 TCP 协议 的开放服务的端口(如一般都会开放的 ECHO 服务端口 7, Linuxssh 服务端口 22 等)。实际上,建立的 TCP 连接被 协议栈放置在连接队列,进而分发到真正处理数据的各个应用服务,由于 UDP 没有连接的过程,因而基于 UDP 的服务(如 SNMP)无法在此方法中应用。

  具体过程是,枚举本地的每个网络地址,建立本地 Socket,在某个端口上尝试连接远 程地址,如果可以连接上,则说明该本地地址可达远程网络。

  程序清单 2:指定本地地址和远程地址,判断两台机 器之间的可达性

  void printReachableIP(InetAddress remoteAddr, int port){

  String retIP = null;

  Enumeration netInterfaces;

  try{

  netInterfaces = NetworkInterface.getNetworkInterfaces();

  while(netInterfaces.hasMoreElements()) {

  NetworkInterface ni = netInterfaces.nextElement();

  Enumeration localAddrs = ni.getInetAddresses();

  while(localAddrs.hasMoreElements()){

  InetAddress localAddr = localAddrs.nextElement();

  if(isReachable(localAddr, remoteAddr, port, 5000)){

  retIP = localAddr.getHostAddress();

  break;

  }

  }

  }

  } catch(SocketException e) {

  System.out.println(

  "Error occurred while listing all the local network addresses.");

  }

  if(retIP == null){

  System.out.println("NULL reachable local IP is found!");

  }else{

  System.out.println("Reachable local IP is found, it is " + retIP);

  }

  }

  boolean isReachable(InetAddress localInetAddr, InetAddress remoteInetAddr,

  int port, int timeout) {

  booleanisReachable = false;

  Socket socket = null;

  try{

  socket = newSocket();

  // 端口号设置为 0 表示在本地挑选一个可用端口进行连接

  SocketAddress localSocketAddr = new InetSocketAddress(localInetAddr, 0);

  socket.bind(localSocketAddr);

  InetSocketAddress endpointSocketAddr =

  new InetSocketAddress(remoteInetAddr, port);

  socket.connect(endpointSocketAddr, timeout);

  System.out.println("SUCCESS - connection established! Local: " +

  localInetAddr.getHostAddress() + " remote: " +

  remoteInetAddr.getHostAddress() + " port" + port);

  isReachable = true;

  } catch(IOException e) {

  System.out.println("FAILRE - CAN not connect! Local: " +

  localInetAddr.getHostAddress() + " remote: " +

  remoteInetAddr.getHostAddress() + " port" + port);

  } finally{

  if(socket != null) {

  try{

  socket.close();

  } catch(IOException e) {

  System.out.println("Error occurred while closing socket..");

  }

  }

  }

  return isReachable;

  }

  运行结果

  --------------START--------------

  FAILRE - CAN not connect! Local: 127.0.0.1 remote: 10.8.1.50 port22

  FAILRE - CAN not connect! Local: 9.123.231.40 remote: 10.8.1.50 port22

  SUCCESS - connection established! Local: 10.0.50.189 remote: 10.8.1.50 port22

  Reachable local IP is found, it is 10.0.50.189

  --------------END--------------

  IPv4 和 IPv6 混合网络下编程

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

  由于 IPv4 和 IPv6 地址之间 是无法互相访问的,因此仅需要判断 IPv4 地址之间和 IPv6 地址之间的可达性。

  对于 IPv4 的换回地址可以不做 判断,对于 IPv6 的 Linklocal 地址也可以跳过测试

  根据实际的需要,我们可以优先考虑选择使用 IPv4 或者 IPv6,提高判断的效率

  程序清单 3: 判断本地地址和远程地址是否同为 IPv4 或者 IPv6

  // 判断是

  IPv4 还是 IPv6

  if(!((localInetAddr instanceofInet4Address) && (remoteInetAddr instanceofInet4Address)

  || (localInetAddr instanceofInet6Address) && (remoteInetAddr instanceofInet6Address))){

  // 本地和远程不是同时是 IPv4 或者 IPv6,跳过这种情况,不作检测

  break;

  }

  程序清单 4:跳过本地地址和 LinkLocal 地址

  if( localAddr.isLoopbackAddress() ||

  localAddr.isAnyLocalAddress() ||

  localAddr.isLinkLocalAddress() ){

  // 地址为本地环回地址,跳过

  break;

  }

  总结和展望

  本文列举集中典型的场景,介绍了通过 Java 网络编程接口判断机器之间可达性的几种方式 。在实际应用中,可以根据不同的需要选择相应的方法稍加修改即可。对于更加特殊的需求,还可以考虑通过 JNI 的方法 直接调用系统 API 来实现,能提供更加强大和灵活的功能,这里就不再赘述了。

赞(0)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程