當前位置:編程學習大全網 - 編程語言 - 如何讓 RMI 程序同時支持 IPv4 和 IPv6

如何讓 RMI 程序同時支持 IPv4 和 IPv6

實踐證明它是健壯,易於實現,並具有很好的互操作性。但是 IPv4 協議的初始設計仍有壹些未考慮到的地方,隨著 Internet 的飛速發展和新型應用的不斷湧現,這些不足逐漸顯露出來。首先,近年來 Internet 成指數級數增長,而只有 32 位地址的 IPv4 引起了迫在眉睫的 IP 地址空間耗盡的問題;第二,IPv4 路由結構較為扁平,使得 Internet 上骨幹路由器需要維護龐大的路由表;第三,目前 IPv4 實現方案中,多數情況需要手工配置或者使用 DHCP 有狀態方式配置協議,隨著越來越多的節點要求接入網絡,需要壹種簡便的配置方式;第四,在 IP 級的安全方面,IPv4 並不強制使用 IPSec ;最後,IPv4 協議中使用服務類型 TOS 字段來支持實時通信流傳送,而 TOS 功能有限,因此對實時數據傳輸 Qos 的支持不是很理想。為解決上述問題及其它相關問題,互聯網工程任務組織 IETF 開發了壹套新的協議和標準即 IP 版本 6(IPv6)。它吸納了很多用於更新 IPv4 的新思想,在設計時力求對上下層協議造成最小的影響。與 IPv4 相比,IPv6 協議具有以下壹些新的特性:IPv6 協議頭采用了固定長度的頭部,路由器在處理 IPv6 報頭時,效率會更高。IPv6 具有 128 位的巨大地址空間,既便為當前所有主機都分配壹個 IPv6 地址,IPv6 仍然有充足的地址供以後使用。IPv6 具有即插即用特性。 IPv6 引入了無狀態地址自動配置方式,鏈路上的主機根據路由公告和自身的鏈路地址可以自動生產壹個 IPv6 地址,從而簡化了入網主機的配置過程,實現了 IPv6 的即插即用。提供網絡層的認證和加密。 IPv6 支持 IPSec,這為網絡安全提供了壹種基於標準的解決方案。IPv6 更好地支持 QoS 。 IPv6 協議頭部包含流標簽字段,使得路由器可以對屬於壹個流的數據包進行識別和提供特殊處理;用業務流分類字段來區分通信流的優先級。因此 IPv6 對 QoS 提供了更好的支持。IPv6 更好地支持移動性。雖然 IPv4 也有移動特性,但是作為 IPv4 的擴展實現,受到體系結構和連通性的限制。而 IPv6 的移動特性是內置的,具有較少的局限性並具有更強的可伸縮性和健壯性,可滿足將來 Internet 的通信需求。IPv6 具有很好的可擴展性,這可通過在 IPv6 協議頭之後添加新的擴展協議頭實現。回頁首Java 對 IPv6 的支持Java 從 1.4 開始,已經提供了對 IPv6 的支持。 Java APIs 遵循了如下 IPv6 標準:RFC2373: IPv6 Addressing ArchitectureRFC2553: Basic Socket Interface Extensions for IPv6RFC2732: Format for Literal IPv6 Address in URL但是由於安全等因素,Java 並沒有支持原始套接字。除此之外,壹些 IPv6 特性,諸如隧道,自動配置,移動 IP 等,Java 都沒有提供支持。與 C/C++ 對 IPv6 的支持不同,Java 對 IPv6 的支持是自動和透明的,也就是說現有的 Java 程序不需要經過修改就可以直接支持 IPv6 。以下面代碼為例,這段代碼在 IPv4 上可以正常運行,同樣也可以工作在 IPv6 上。InetAddress ip = InetAddress.getByName("java.sun.com"); Socket s = new Socket(ip, 80);Java 對 IPv6 的支持體現在其 JDK 對 IPv6 的支持上,當然前提條件是操作系統需要提供對 IPv6 的支持。以下操作系統已經提供了對 IPv6 的支持,表1. OS 對 IPv6 的支持Windows:Windows 2000Windows XPWindows NTWindows 2003 serverLinux:Linux kernel 2.2 及以上版本Unix:AIX 4.3 及以上版本Solaris 8 及以上版本HP-UX 11i 及以上版本BSD/OS 4.0 及以上版本True64 Unix 4.0D 及以上版本FreeBSD 4.0 及以上版本NetBSDOpenBSD 2.7 及以上版本Other OS:OS/390, Z/OS V1R4 及以上版本OS400 V5R2 及以上版本Mac OS X下面列出了各個版本 JDK 對 IPv6 的支持情況。表2. JDK 對 IPv6 的支持JDK/OSWindowsLinuxAIXSolarisHPUXZOSIBM JDK 1.4NOYESYESNOIBM JDK 1.5YESYESYESYESSUN JDK 1.4NOYESYESSUN JDK 1.5YESYESYESJRockit JDK 1.4NOYESJRockit JDK 1.5YESYESHP-UX JDK 1.4YESHP-UX JDK 1.5YES回頁首RMI 對 IPv6 的支持既然Java 對 IPv6 的支持是透明的,那麽 RMI 程序理論上就應該同時支持 IPv4 和 IPv6,但測試結果告訴我們只有在 RMI 服務器端套接字不綁定 IP 地址的情況下這種結論才成立。考慮下面這樣壹個例子,壹個支持雙棧的服務器,同時配置了 IPv4 地址和 IPv6 地址。服務器應用程序用如下代碼創建了壹個服務器套接字,等待客戶端的連接。由於 Java 對 IPv6 的透明支持,IPv4 和 IPv6 的客戶端都可以正常連接到這臺服務器上。清單1. 無 IP 綁定的服務器套接字程序 try { int port = 2000; ServerSocket srv = new ServerSocket(port); Socket socket = srv.accept(); } catch (IOException e) { e.printStackTrace(); }通過natestat – na可以看出,服務器監聽在 0.0.0.0:2000 上,這樣任何客戶端都可以連接到服務器上,其中包括 IPv6 客戶端用服務器的 IPv6 地址也能順利連接。Proto Local Address Foreign Address State TCP 0.0.0.0:2000 0.0.0.0:0 LISTENING但是很多時候,應用程序從安全等角度考慮,常常需要將服務器套接字綁定在某個具體的 IP 上。現在我們假設把服務器套接字綁定在壹個 IPv4 地址上,如下程序所示:清單2. 綁定 IP 的服務器套接字程序 try { int port = 2000; ServerSocket srv = new ServerSocket(port); srv.bind(new InetSocketAddress( “ 9.181.27.34 ” , port) Socket socket = srv.accept(); } catch (IOException e) { e.printStackTrace(); }通過natestat – na,我們可以發現監聽方式已改變: Proto Local Address Foreign Address State TCP 9.181.27.34:2000 0.0.0.0:0 LISTENING從套接字的定義看出,它由 IP 和端口組成,它們唯壹確定了壹個套接字,同時也限定了訪問套接字的方式。在訪問由固定 IP 和端口組成的套接字時,客戶端必須指定服務器的 IP 和端口才能正常連接。在服務器綁定 IPv4 地址的情況下,IPv6 客戶端就無法用服務器的 IPv6 地址進行訪問,當然 IPv4 客戶端能通過服務器的 IPv4 地址 9.181.27.34 進行連接訪問。上面分析了 Java 對 IPv6 的支持以及服務器套接字如何影響客戶端的連接,接下來我們用實例分析 RMI 對 IPv6 的支持。我們搭建了如下的實驗環境:圖1. 實驗環境接下來,我們設計了壹個基本的 RMI 應用程序,下面這段是 RMI 服務器程序:清單3. RMI 服務器程序 import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*; public class SampleServerImpl extends UnicastRemoteObject implements SampleServer { SampleServerImpl() throws RemoteException { super(); } public int sum(int a,int b) throws RemoteException { return a + b; } public static void main(String args[]) { try { //create a local instance of the object SampleServerImpl Server = new SampleServerImpl(); //put the local instance in the registry Naming.rebind("rmi://9.181.27.34/SAMPLE-SERVER" , Server); System.out.println("Server waiting....."); } catch (java.net.MalformedURLException me) { System.out.println("Malformed URL: " + me.toString()); } catch (RemoteException re) { System.out.println("Remote exception: " + re.toString()); } } }編譯源程序,啟動rmiregistry,然後運行 RMI 服務器程序。通過netstat – na我們可以看見,RMI 監聽方式如下,盡管我們在程序中用了”Naming.rebind("rmi://9.181.27.34/SAMPLE-SERVER" , Server)”:Proto Local Address Foreign Address State TCP 0.0.0.0:1099 0.0.0.0:0 LISTENING那麽,根據我們上面關於套接字對客戶端連接的影響的分析,我們可以看出在這種情況下,IPv4 RMI 客戶端和 IPv6 RMI 客戶端都應該能夠順利連接 RMI 服務器。下面我們就看壹下 IPv4 客戶端的連接程序:清單4. RMI 客戶端程序 import java.rmi.*; import java.rmi.server.*; public class SampleClient { public static void main(String[] args) { //get the remote object from the registry try { //using RMI server ’ s IPv4 address to connect String url = "//9.181.27.34/SAMPLE-SERVER"; SampleServer remoteObject = (SampleServer)Naming.lookup(url); System.out.println("Got remote object"); System.out.println(" 1 + 2 = " + remoteObject.sum(1,2) ); } catch (RemoteException exc) { System.out.println("Error in lookup: " + exc.toString()); } catch (java.net.MalformedURLException exc) { System.out.println("Malformed URL: " + exc.toString()); } catch (java.rmi.NotBoundException exc) { System.out.println("NotBound: " + exc.toString()); } } }編譯並運行該程序,可以看到正常連接到 RMI 服務器,運行結果如下:Got remote object 1 + 2 = 3下面我們在 IPv4 RMI 客戶端程序的基礎上作壹下改動,用 RMI 服務器的 IPv6 地址進行連接,修改如下:String url = "//2001:251:1a05::6/SAMPLE-SERVER"; SampleServer remoteObject = (SampleServer)Naming.lookup(url);編譯修改之後的程序,在 IPv6 RMI 客戶端上運行,同樣可以正常連接 RMI 服務器,運行結果如下:Got remote object 1 + 2 = 3通過這個例子,我們可以看出基本的 RMI 程序對 IPv6 的支持是透明的,它可以同時支持 IPv4 和 IPv6 。通過這個例子,我們也可以看出,它實際上不能綁定 IP 地址,這在安全性要求比較高的企業級應用程序中並不是很合適,它們通常采用UnicastRemoteObject類的exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)方法來綁定 RMI IP 地址。在RMIServerSocketFactory實例中,創建 RMI 服務器套接字並綁定 IP 地址,在RMIClientSocketFactory實例中通過服務器綁定的 IP 地址進行訪問。在RMI 服務器綁定 IP 地址的情況,如果讓 RMI 同時支持 IPv4 和 IPv6 呢?下面給出了壹個解決方案。既然要讓 RMI 同時支持 IPv4 和 IPv6,那麽在服務器端,我們就要同時創建兩個套接字,壹個綁定在 IPv4 地址上,壹個綁定在 IPv6 地址上。首先,我們應該創建兩個類IPv4RMIServerSocket和IPv6RMIServerSocket,他們都實現RMIServerSocketFactory接口。IPv4RMIServerSocket創建壹個服務器套接字並綁定在 RMI 服務器的 IPv4 地址上;IPv6RMIServerSocket創建壹個服務器套接字並綁定在 RMI 服務器的 IPv6 地址上。其次,在創建兩個類IPv4RMIClientSocket和IPv6RMIClientSocket,他們都實現RMIClientSocketFactory接口。IPv4RMIClientSocket創建壹個客戶端套接字並通過 RMI 服務器的 IPv4 地址進行連接;IPv6RMIClientSocket創建壹個客戶端套接字並通過 RMI 服務器的 IPv6 地址進行連接。然後,在創建好我們需要的服務器和客戶端類之後,服務器應用程序需要兩次調用exportObject方法將遠程對象導出。但是有壹個問題出現了,同壹個遠程對象不能同時導出兩次。如何解決這個問題呢?辦法就是我們需要對遠程對象作壹個wrapper。現在假設有壹個遠程對象Kernel的類定義如下:清單5. Kernel 類定義 public class Kernel extends Remote{ public void addWebServer(String hostName, int port) throws RemoteException { //Function implementation code } public void changeLogLevel(int level) throws RemoteException { //Function implementation code } }Kernel 的 Wrapper 定義如下:清單6. Kernel 的 Wrapper 類定義 public class KernelWrapper extends Remote { transient Kernel kernel_; public KernelWrapper (Kernel kernel) throws RemoteException, IOException { super(); kernel_ = kernel; } public void addWebServer(String hostName, int port) throws RemoteException { kernel_.addWebServer(hostName, port); } public void changeLogLevel(int level) throws RemoteException { kernel_.changeLogLevel(level); } }在應用程序初始化的時候,實例化壹個 Kernel 實例,並將它作為參數實例化兩個 KernelWrapper 實例,如下所示:清單7. KernelWrapper 實例化 kernelObj = new Kernel(); //remote kernel object for IPv4 clients ipv4kernelObj = new KernelWrapper (kernelObj); //remote kernel object for IPv6 clients ipv6kernelObj = new KernelWrapper (kernelObj);最後應用程序需要將 ipv4kernelObj 和 ipv6kernelObj 遠程對象導出,如下所示:清單8. 遠程對象導出 //export remote object for IPv4 client UnicastRemoteObject.exportObject( ipv4kernelObj, 1099, IPv4RMIClientSocket, IPv4RMIServerSocket ) //export remote object for IPv6 client UnicastRemoteObject.exportObject( ipv6kernelObj, 1099, IPv6RMIClientSocket, IPv6RMIServerSocket )這樣IPv4 客戶端通過服務器的 IPv4 地址進行訪問,而 IPv6 客戶端通過服務器的 IPv6 地址進行訪問,從而成功的使得 RMI 服務器在綁定 IP 地址的情況下同時支持 IPv4 和 IPv6 。回頁首結束語本文在分析服務器套接字對 IPv4 和 IPv6 客戶端的影響的基礎上,介紹了兩種不同的 RMI 應用對 IPv6 的支持情況,同時給出了壹種 RMI 服務器在需要綁定 IP 地址的情況下如何同時支持 IPv4 和 IPv6 客戶端的解決方案。參考資料 IPv6 主頁:IPv6 官方網站。

Networking IPv6 User Guide for J2SDK/JRE 1.4:JDK 1.4 對 IPv6 的支持。

An example of RMI programming:RMI 的簡單例子。

“探索Internet Protocol, version 6 (IPv6)”(developerWorks,2006 年 7 月):了解 IPv6 的地址格式、主要優點和符合新標準的 IT 產品。

“配置FTP 服務器以支持 IPv6”(developerWorks,2006 年 8 月):在本文中,學習配置 File Transfer Protocol (FTP) 服務器以支持 IPv6,然後通過壹個簡單的使用 IPv6 地址的 Java 程序來與 FTP 服務器通信。

“結合使用 WebSphere Application Server V7 和 IPv6”(developerWorks,2008 年 11 月):本文將介紹用於驗證 IBM WebSphere Application Server V7 的過程,以驗證其對 IPv6 以及對 IPv4/IPv6 混合模式基礎結構的支持。

developerWorks Java 技術專區:這裏有數百篇關於 Java 編程的文章。

關於作者沈剛目前在 IBM Tivoli 部門從事 ITM for Applications 產品開發工作。關閉[x]關於報告濫用的幫助報告濫用謝謝! 此內容已經標識給管理員註意。關閉[x]關於報告濫用的幫助報告濫用報告濫用提交失敗。 請稍後重試。關閉[x]developerWorks:登錄IBM ID:需要壹個 IBM ID?忘記IBM ID?密碼:忘記密碼?更改您的密碼 保持登錄。單擊提交則表示您同意developerWorks 的條款和條件。 使用條款 當您初次登錄到 developerWorks 時,將會為您創建壹份概要信息。您在developerWorks 概要信息中選擇公開的信息將公開顯示給其他人,但您可以隨時修改這些信息的顯示狀態。您的姓名(除非選擇隱藏)和昵稱將和您在 developerWorks 發布的內容壹同顯示。所有提交的信息確保安全。關閉[x]請選擇您的昵稱:當您初次登錄到 developerWorks 時,將會為您創建壹份概要信息,您需要指定壹個昵稱。您的昵稱將和您在 developerWorks 發布的內容顯示在壹起。昵稱長度在 3 至 31 個字符之間。 您的昵稱在 developerWorks 社區中必須是唯壹的,並且出於隱私保護的原因,不能是您的電子郵件地址。昵稱:(長度在 3 至 31 個字符之間)單擊提交則表示您同意developerWorks 的條款和條件。 使用條款. 所有提交的信息確保安全。為本文評分評論回頁首

  • 上一篇:四年級小小動物園作文
  • 下一篇:手機裏照片太多,占內存太多該怎麽辦
  • copyright 2024編程學習大全網