在实际的Java程序中使用IPv6

IPv6的使用现在正在慢慢开始,所以我目前正在修复和更新所有为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.preferIPv6Addresses设置为true以使其使用IPv6。 结果是关于互联网连接中断的用户错误报告。

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

当IPv6通过隧道传输时,OS通常也更喜欢IPv4而不是IPv6。 看起来Java也忽略了这个设置。

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

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

所以你有两个问题:

  1. 操作系统供应商提供具有损坏的默认IPv6配置的操作系统,和/或用户启用损坏的IPv6配置。

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

你可以在这做两件事:

  1. 建议用户如何禁用不必要和破坏的IPv6过渡机制,如Teredo,ISATAP和6to4。 有关这些的说明可在因特网上广泛获得。

    如果某些操作系统供应商默认情况下不启用此垃圾也会很好,但这可能要求太多。

  2. 在您的应用程序中实现Happy Eyeballs( RFC 6555 )。 这就是现代Web浏览器如何解决这个问题。

    Happy Eyeballs指定一种算法,即应用程序尝试(几乎)同时通过IPv6和IPv4进行连接,如果IPv6在短时间内无法工作,则回退到IPv4连接。 该试验的结果也缓存了几分钟。

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

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

  • 该软件检测IPv6是否工作并记住状态 – >这是通过TCP连接到已知的IPv6地址(Ping of 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(); } }