標籤:鍵盤輸入 mda exception pack 過濾 click exce 思路 存在
IPv6編程——Java1. Java支援IPv6
Java 從 1.4 版開始支援 Linux 和Solaris 平台上的 IPv6。1.5 版起又加入了 Windows 平台上的支援。
在 IPv6 的環境下開發 Java 應用,或者移植已有的 IPv4 環境下開發的Java 應用到 IPv6 環境中來,對於 IPv6 網路地址的驗證是必須的步驟,尤其是對那些提供了 UI(使用者介面)的 Java 應用。
2. 擷取本機IPv6地址
有時為了能夠註冊 listener,開發人員需要使用原生 IPv6 地址,這一地址不能簡單得通過 InetAddress.getLocalhost() 獲得。因為這樣有可能獲得諸如 0:0:0:0:0:0:0:1 這樣的特殊地址。使用這樣的地址,其他伺服器將無法把通知發送到本機上,因此必須先進行過濾,選出確實可用的地址。以下代碼實現了這一功能,思路是遍曆網路介面的各個地址,直至找到符合要求的地址。
package com.text;import java.io.IOException;import java.net.Inet6Address;import java.net.InetAddress;import java.net.NetworkInterface;import java.util.Enumeration;public class Get_IPv6 { public static void main(String[] args) throws IOException{ String str = getLocalIPv6Address(); System.out.println(str); } public static String getLocalIPv6Address() throws IOException { InetAddress inetAddress = null; Enumeration<NetworkInterface> networkInterfaces = NetworkInterface .getNetworkInterfaces(); outer: while (networkInterfaces.hasMoreElements()) { Enumeration<InetAddress> inetAds = networkInterfaces.nextElement() .getInetAddresses(); while (inetAds.hasMoreElements()) { inetAddress = inetAds.nextElement(); //Check if it‘s ipv6 address and reserved address if (inetAddress instanceof Inet6Address && !isReservedAddr(inetAddress)) { break outer; } } } String ipAddr = inetAddress.getHostAddress(); // Filter network card No int index = ipAddr.indexOf(‘%‘); if (index > 0) { ipAddr = ipAddr.substring(0, index); } return ipAddr; } private static boolean isReservedAddr(InetAddress inetAddr) { if (inetAddr.isAnyLocalAddress() || inetAddr.isLinkLocalAddress() || inetAddr.isLoopbackAddress()) { return true; } return false; }}
為了支援 IPv6,Java 中增加了兩個 InetAddress 的子類:Inet4Address和 Inet6Address。一般情況下這兩個子類並不會被使用到,但是當我們需要分別處理不同的 IP 協議時就非常有用,在這我們根據Inet6Address來篩選地址。
isReservedAddr() 方法過濾了本機特殊 IP 位址,包括“LocalAddress”,“LinkLocalAddress”和“LoopbackAddress”。另一個需要注意的地方是:在 windows 平台上,取得的 IPv6 地址後面可能跟了一個百分比符號加數字。這裡的數字是本機網路介面卡的編號。這個尾碼並不是 IPv6 標準地址的一部分,可以去除。
3. IPv4/IPv6 雙環境下,網路的選擇和測試
Java 提供了 InetAddress 的兩個擴充類以供使用:Inet4Address 和 Inet6Address,其中封裝了對於 IPv4 和 IPv6 的特殊屬性和行為。然而由於Java 的多態特性,使得程式員一般只需要使用父類 InetAddress,JAVA 虛擬機器可以根據所封裝的 IP 位址類型的不同,在運行時選擇正確的行為邏輯。所以在多數情況下,程式員並不需要精確控制所使用的類型及其行為,一切交給 Java虛擬機器即可。具體的新增類型及其新增方法,請具體參閱 Sun 公司的 JavaDoc。
在 IPv4/IPv6 雙環境中,對於使用 Java 開發的網路應用,比較值得注意的是以下兩個 IPv6 相關的 JAVA 虛擬機器系統屬性。
java.net.preferIPv4Stack=<\true|false>
java.net.preferIPv6Addresses=<\true|false>
程式中設定代碼如下:
System.setProperty("java.net.preferIPv6Addresses","true");
preferIPv4Stack(預設 false)表示如果存在 IPv4 和 IPv6 雙棧,Java 程式是否優先使用 IPv4 通訊端。預設值是優先使用 IPv6 通訊端,因為 IPv6 通訊端可以與對應的 IPv4 或 IPv6 主機進行對話;相反如果優先使用 IPv4,則只不能與 IPv6 主機進行通訊。
preferIPv6Addresses(預設 false)表示在查詢本地或遠端 IP 位址時,如果存在 IPv4 和 IPv6 雙地址,Java 程式是否優先返回 IPv6 地址。Java 預設返回 IPv4 地址主要是為了向後相容,以支援舊有的 IPv4 驗證邏輯,以及舊有的僅支援 IPv4 地址的服務。
4. socket 支援 IPv6 通訊樣本
用戶端:
package com.text2;import java.io.BufferedReader;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.Inet6Address;import java.net.InetAddress;import java.net.NetworkInterface;import java.net.Socket;import java.util.Enumeration;public class Click { public static void main(String[] args) throws IOException { //擷取本機IPv6地址getLocalIPv6Address()方法在上面已經提到 String servernameString = getLocalIPv6Address(); System.out.println("用戶端啟動…"); System.out.println("當接收到伺服器端字元為 \"OK\" 的時候, 用戶端將終止\n"); while (true) { Socket socket = null; try { // 建立一個流通訊端並將其串連到指定主機上的指定連接埠號碼 socket = new Socket(servernameString, 8080); // 讀取伺服器端資料 DataInputStream input = new DataInputStream(socket.getInputStream()); // 向伺服器端發送資料 DataOutputStream out = new DataOutputStream(socket.getOutputStream()); System.out.print("請輸入: \t"); String str = new BufferedReader(new InputStreamReader(System.in)).readLine(); out.writeUTF(str); String ret = input.readUTF(); System.out.println("伺服器端返回過來的是: " + ret); if ("OK".equals(ret)) { System.out.println("用戶端將關閉串連"); Thread.sleep(500); break; } out.close(); input.close(); } catch (Exception e) { System.out.println("用戶端異常:" + e.getMessage()); } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { socket = null; System.out.println("用戶端 finally 異常:" + e.getMessage()); } } } } } public static String getLocalIPv6Address() throws IOException { InetAddress inetAddress = null; Enumeration<NetworkInterface> networkInterfaces = NetworkInterface .getNetworkInterfaces(); outer: while (networkInterfaces.hasMoreElements()) { Enumeration<InetAddress> inetAds = networkInterfaces.nextElement() .getInetAddresses(); while (inetAds.hasMoreElements()) { inetAddress = inetAds.nextElement(); //Check if it‘s ipv6 address and reserved address if (inetAddress instanceof Inet6Address && !isReservedAddr(inetAddress)) { break outer; } } } String ipAddr = inetAddress.getHostAddress(); // Filter network card No int index = ipAddr.indexOf(‘%‘); if (index > 0) { ipAddr = ipAddr.substring(0, index); } return ipAddr; } private static boolean isReservedAddr(InetAddress inetAddr) { if (inetAddr.isAnyLocalAddress() || inetAddr.isLinkLocalAddress()|| inetAddr.isLoopbackAddress()) { return true; } return false; }}
伺服器端:
package com.text2;import java.io.BufferedReader;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;public class Server { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("伺服器啟動…\n"); Server server = new Server(); server.init(); } public void init() { try { ServerSocket serverSocket = new ServerSocket(8080); while (true) { // 一旦有堵塞, 則表示伺服器與用戶端獲得了串連 Socket client = serverSocket.accept(); // 處理這次串連 new HandlerThread(client); } } catch (Exception e) { System.out.println("伺服器異常: " + e.getMessage()); } } private class HandlerThread implements Runnable { private Socket socket; public HandlerThread(Socket client) { socket = client; new Thread(this).start(); } public void run() { try { // 讀取用戶端資料 DataInputStream input = new DataInputStream(socket.getInputStream()); String clientInputStr = input.readUTF(); //這裡要注意和用戶端輸出資料流的寫方法對應,否則會拋 EOFException // 處理用戶端資料 System.out.println("用戶端發過來的內容:" + clientInputStr); // 向用戶端回複資訊 DataOutputStream out = new DataOutputStream(socket.getOutputStream()); System.out.print("請輸入:\t"); // 發送鍵盤輸入的一行 String s = new BufferedReader(new InputStreamReader(System.in)).readLine(); out.writeUTF(s); out.close(); input.close(); } catch (Exception e) { System.out.println("伺服器 run 異常: " + e.getMessage()); } finally { if (socket != null) { try { socket.close(); } catch (Exception e) { socket = null; System.out.println("服務端 finally 異常:" + e.getMessage()); } } } } }}
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
IPv6基本編程——Java