2013-04-23 84 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(); 
    } 
}