java - 在实际 Java 程序中使用 IPv6

标签 java network-programming 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 被隧道传输时,操作系统通常更喜欢 IPv4 而不是 IPv6。 Java 似乎也忽略了此设置。

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

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

最佳答案

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

  • 软件会检测 IPv6 是否工作并记住状态 -> 这是通过与已知 IPv6 地址建立 TCP 连接来完成的(isReachable() 的 Ping 不可靠,请参阅此错误报告: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();
  }
}

关于java - 在实际 Java 程序中使用 IPv6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16164175/

相关文章:

java - 在随机方法中测试特定数字时,我得到的结果好坏参半

java - 检查套接字是否仍然打开

java - xml转换编码问题

perl - 在Perl中将域名转换为IPv6地址

python - 为什么 python 的 ipv6 连接失败?

networking - IPv6 零压缩

Java在方法中访问字符串数组

在多线程程序中关闭文件描述符

sockets - 套接字API : why `connect` doesn't return a descriptor?

java - Netty 相对于基本 ServerSocket 服务器的优势?