2013-04-23 83 views
7

IPv6的使用现在正在慢慢开始,所以我目前正在修复和更新所有为IPv6准备的应用程序。在真实世界的Java程序中使用IPv6

其中一个应用程序是Java编辑器JOSM(http://josm.openstreetmap.de/)。即使操作系统使用IPv6,Java也不会在默认配置中使用IPv6。

根据 http://docs.oracle.com/javase/1.5.0/docs/guide/net/ipv6_guide/#using 我设置java.net.preferIPv6Addressestrue让它使用IPv6。结果是关于互联网连接断开的用户错误报告。

看来Java只会切换到使用IPv6地址而不使用IPv4,但除此之外别无其他。我维护的所有基于C/C++的软件都已更改为检查并尝试所有可用的IP地址,因此只要其中一个地址有效,跳过的IPv6(或IPv4)地址就会被跳过。对我来说,Java看起来只会尝试一次,这在现实世界中不起作用。

通常,当IPv6隧道传输时,操作系统更喜欢IPv4 over IPv6。 Java似乎也忽略了这些设置。

所以我的问题是:是否有任何好的方法让默认情况下使用IPV6的Java应用程序在不破坏IPv4用户应用程序的情况下可用。

用户错误报告:http://josm.openstreetmap.de/ticket/8562http://josm.openstreetmap.de/ticket/8627

回答

0

所以,你这里有两个问题:

  1. 操作系统厂商船操作系统与破坏默认IPv6配置,和/或用户能破IPv6配置。

  2. 当它不起作用时,他们错误地责怪你。

有两件事情,你可以在这里做:

  1. 有关如何禁用不必要的和破碎的IPv6过渡机制,如Teredo的,ISATAP和的6to4建议用户。这些指令在互联网上广泛使用。

    如果某些操作系统供应商默认不启用此垃圾,那也不错,但这可能要求太高。

  2. 在您的应用程序中实施快乐眼球(RFC 6555)。这是现代Web浏览器如何解决这个问题。

    快乐眼球规定了一种算法,由此应用程序试图经由IPv6和IPv4在(几乎)同时进行连接,并且如果IPv6的不很短的时间量内工作,回落到IPv4连接。这个试验的结果也被缓存了几分钟。

    不幸的是,我并不熟悉Java为您提供特定的代码,以绕过Oracle默认隐藏的所有有趣东西,但它是可行的。

+0

Java对于完全有效的系统也是失败的,其中IPV6仅用于本地,因为这些系统使用IPv6,而系统本身知道它没有IPv6连接。你的建议根本没有帮助。首先,我无法修复我们用户的所有安装。其次,我不知道如何取代Java中完整的网络处理。我需要一个真实世界的解决方案,而不仅仅是学术上的兴趣。 – 2013-04-24 07:52:51

+0

对不起。如果是其他语言,我可以给你大量的示例代码。不过,这是你应该走的方向。 – 2013-04-24 14:58:47

+0

你误解了复杂性。这个软件没有一个地方可以访问网络。可能有数百个不同的职位,其中一些职位隐藏在Java系统的深处。因此,为了让您的建议成立,必须有可能立即替换整个网络连接处理。我认为这不是一件容易的事(但也许有人知道一种方式)。目前,我们遇到的问题是向正在发布的所有HTTP连接添加正确的用户代理(对于其中一些而言没有问题,但对所有人来说都很难)。 – 2013-04-24 15:11:24

0

看来这个话题对其他人来说也很有趣,所以我描述了我目前的解决方案。

  • 软件做一个检测的IPv6是否工作并记住状态 - >这是做一个TCP连接到已知的IPv6地址来实现(isReachable平安()是不可靠的,看到这个错误报告: https://josm.openstreetmap.de/ticket/11452)。
  • 基于记忆状态,软件以“java.net.preferIPv6Addresses”设置为“true”开始。
  • 这意味着从IPv4切换到IPv6网络时,它将使用IPv4,直到下次重新启动为止。
  • 对于从支持IPv6的网络切换到仅支持IPv4的网络,根本无法通过重新启动软件解决。
  • 如有疑问,我们假设IPv6不起作用。
  • 检测后无法更改“java.net.preferIPv6Addresses”,因为这些值似乎只能在第一次网络连接之前读取。如果有在运行时重置该状态的方法,我想知道它。

这个解决方案似乎有效,我们在日志ATM中有大约4%的IPv6连接,但这不是一个令人满意的解决方案。

/** 
* Check if IPv6 can be safely enabled and do so. Because this cannot be done after network activation, 
* disabling or enabling IPV6 may only be done with next start. 
*/ 
private static void checkIPv6() { 
    if ("auto".equals(Main.pref.get("prefer.ipv6", "auto"))) { 
    new Thread(new Runnable() { /* this may take some time (DNS, Connect) */ 
     public void run() { 
     boolean hasv6 = false; 
     boolean wasv6 = Main.pref.getBoolean("validated.ipv6", false); 
     try { 
      /* Use the check result from last run of the software, as after the test, value 
      changes have no effect anymore */ 
      if (wasv6) { 
      Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true"); 
      } 
      for (InetAddress a : InetAddress.getAllByName("josm.openstreetmap.de")) { 
      if (a instanceof Inet6Address) { 
       if (a.isReachable(1000)) { 
       /* be sure it REALLY works */ 
       Socket s = new Socket(); 
       s.connect(new InetSocketAddress(a, 80), 1000); 
       s.close(); 
       Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true"); 
       if (!wasv6) { 
        Main.info(tr("Detected useable IPv6 network, prefering IPv6 over IPv4 after next restart.")); 
       } else { 
        Main.info(tr("Detected useable IPv6 network, prefering IPv6 over IPv4.")); 
       } 
       hasv6 = true; 
       } 
       break; /* we're done */ 
      } 
      } 
     } catch (IOException | SecurityException e) { 
      if (Main.isDebugEnabled()) { 
      Main.debug("Exception while checking IPv6 connectivity: "+e); 
      } 
     } 
     if (wasv6 && !hasv6) { 
      Main.info(tr("Detected no useable IPv6 network, prefering IPv4 over IPv6 after next restart.")); 
      Main.pref.put("validated.ipv6", hasv6); // be sure it is stored before the restart! 
      new RestartAction().actionPerformed(null); 
     } 
     Main.pref.put("validated.ipv6", hasv6); 
     } 
    }, "IPv6-checker").start(); 
    } 
}