IPv4 的 32 位地址空間(約 43 億)已近枯竭,且 NAT 破壞了端到端連接性。IPv6 以 128 位地址(3.4×10³⁸)徹底解決數量問題,並原生支持移動性、自動配置、IPsec,為物聯網、車聯網、工業互聯網奠定基礎。過渡期漫長,雙棧(Dual Stack)是主流共存方案。
| 棧類型 | 客戶端行為 | 服務端行為 | UDP 行為 |
|---|---|---|---|
| 真雙棧 | 創建 IPv6 Socket,自動兼容 IPv4(映射地址) | 單一 IPv6 Socket 監聽 :: | 單一 IPv6 Socket |
| 分離雙棧 | 同時創建 IPv4/IPv6 兩個 Socket,先連成功者生效,另一關閉 | 同時保留 IPv4/IPv6 兩個 Socket 監聽 | 保留兩個 Socket 並行通信 |
8 組 16 進制,冒號分隔:2001:0db8:85a3:08d3:1319:8a2e:0370:7344
0db8 → db8:: 壓縮(僅一次):2001:db8::1::ffff:192.0.2.1 或 ::192.0.2.1// 推薦:標準庫方法
boolean valid = sun.net.util.IPAddressUtil.isIPv6LiteralAddress(ipStr);
注意:此類為內部 API,跨版本可能變更。生產環境建議自行實現或使用第三方庫(如 Apache Commons Validator)。
public static boolean isIPv6Format(String ip) {
ip = ip.trim();
// 移除 URL 中的方括號包裹
if (ip.startsWith("[") && ip.endsWith("]")) {
ip = ip.substring(1, ip.length() - 1);
}
// 基礎結構檢查
String[] parts = ip.split(":");
if (parts.length < 2 || parts.length > 8) return false; // 至少 1 個冒號,最多 7 個
if (ip.split("::").length > 2) return false; // :: 只能出現一次
// 分類正則匹配(略,完整代碼見原文)
// 策略:根據 :: 位置(開頭/中間/結尾)及是否包含 IPv4 嵌入,分別匹配
// 優點:邏輯清晰、易擴展、跨語言移植簡單
}
同一 IPv6 地址有多種文本形式,作為 Map Key、日誌記錄、ACL 匹配時必須正規化。
InetAddress addr = InetAddress.getByName(ipStr);
String normalized = addr.getHostAddress(); // 返回完整展開形式,如 2002:97b:e7aa:0:0:0:97b:e7aa
InetAddress.getByName() 接受主機名或 IP 字符串,內部調用系統解析器,自動處理壓縮、嵌入 IPv4 等格式。
InetAddress.getLocalHost() 常返回回環地址(::1)或鏈路本地地址(fe80::/10),不可用於服務註冊。
public static String getLocalIPv6Address() throws SocketException {
Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
Enumeration addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = addresses.nextElement();
if (addr instanceof Inet6Address && !isReservedAddr(addr)) {
String ip = addr.getHostAddress();
// Windows 下移除區域 ID 後綴(如 %eth0)
int idx = ip.indexOf('%');
return idx > 0 ? ip.substring(0, idx) : ip;
}
}
}
return null;
}
private static boolean isReservedAddr(InetAddress addr) {
return addr.isAnyLocalAddress() // ::/128
|| addr.isLoopbackAddress() // ::1/128
|| addr.isLinkLocalAddress(); // fe80::/10
}
關鍵點:遍歷網卡接口,過濾保留/回環/鏈路本地地址,處理 Windows 區域 ID 後綴。
| 屬性 | 默認值 | 作用 | 建議 |
|---|---|---|---|
java.net.preferIPv4Stack | false | true=強制用 IPv4 Socket | 一般保持 false,利用 IPv6 Socket 雙棧特性 |
java.net.preferIPv6Addresses | false | true=優先返回 IPv6 地址 | 兼容舊系統保持 false;新系統可設 true |
啟動示例:java -Djava.net.preferIPv6Addresses=true MyApp
InetAddress 多態:業務代碼面向父類,JVM 運行時自動分派 Inet4Address/Inet6AddressgetHostAddress() 輸出Java 對 IPv6 的支持成熟且透明,核心在於:理解雙棧 Socket 行為、善用 InetAddress 多態、正規化地址表示、配置正確的 JVM 參數。遷移關鍵不在代碼修改量,而在於基礎設施(DNS、路由、防火牆)的 IPv6 就緒。掌握本文驗證、正規化、本機地址獲取等實用技巧,可構建真正面向未來的網絡應用。