相关文章推荐
腼腆的小摩托  ·  CCTV.com-台湾男歌手张震岳:地球人都 ...·  7 月前    · 
逼格高的蜡烛  ·  花样青春:非洲篇_百度百科·  8 月前    · 
爱听歌的鞭炮  ·  世界唯一以长寿为特色的景区,期颐老人遍布,最 ...·  1 年前    · 
奔放的松树  ·  2022天津外国语大学录取分数线(含2020 ...·  1 年前    · 
悲伤的鸭蛋  ·  天才在疯子左右正版包邮天才在左疯子在右高铭著 ...·  1 年前    · 
小百科  ›  Java对IPv6的鼓励浅谈:鼓励情况、前述API、演示代码等-腾讯云开发者社区-腾讯云
网络地址 网络验证 ipv6
慷慨大方的莲藕
1 年前
作者头像
JackJiang
0 篇文章

Java对IPv6的支持详解:支持情况、相关API、演示代码等

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > 即时通讯技术 > Java对IPv6的支持详解:支持情况、相关API、演示代码等

Java对IPv6的支持详解:支持情况、相关API、演示代码等

作者头像
JackJiang
修改 于 2020-12-08 10:16:51
1.3K 0
修改 于 2020-12-08 10:16:51
举报

本文由朱益盛、杨晖、傅啸分享,来自IBM Developer社区,原题“使用 Java 开发兼容 IPv6 的网络应用程序”,本次收录时有改动。

1、引言

前几天,有个群友跟我讨论用 MobileIMSDK 写的IM服务端想支持IPv6的问题。因为众所周之的原因,IPv4早就不够用,现在国内从国家层面都在大力推广IPv6的普及,所以包括事业单位、国企在内,现在搞信息化建议,都要考虑IPv6的支持。

我忽然感觉这个问题很难回答,因为对于普通的网络通信程序开发者来说,目前真正的IPv6的开发和测试环境并不容易得到,所以想要真正说清楚Java对于IPv6地支持情况,只能借助零碎的资料和网贴,可能并不完整和准备。

理论上,Java对IPv6的支持对于程序员来说都是透明的,几乎不需要代码层面的处理。但它到底是怎么支持的?支持到什么程度?对JDK版本有什么要求?对操作系统有什么要求?等等,我认为还是有必要详细研究了解一下。

本文将用通俗易懂的文字,来讲解Java对IPv6的支持现状,包括关的技术原理、可以使用的API、以及一些可以运行的演示代码片段等,希望能让你更直观的了解Java对于IPv6的支持情况。

阅读提示: 限于篇幅,本文假设你已了解IPv6技术是什么,如您对它一无所知,建议先阅读白话式入门文章:《 一文读懂什么是IPv6 》。

2、推荐资料

《 IPv6技术详解:基本概念、应用现状、技术实践(上篇) 》 《 IPv6技术详解:基本概念、应用现状、技术实践(下篇) 》

3、技术背景

目前我们使用的是第二代互联网 IPv4 技术,它的最大问题是网络地址资源有限,从理论上讲,可以编址 1600 万个网络、40 亿台主机。但采用 A、B、C 三类编址方式后,可用的网络地址和主机地址的数目大打折扣,以至目前的 IP 地址近乎枯竭。网络地址不足,严重地制约了全球互联网的应用和发展。

▲ 本图引用自《 网络编程懒人入门(十一):一文读懂什么是IPv6 》

一方面是地址资源数量的限制,另一方面是随着电子技术及网络技术的发展,计算机网络将进入人们的日常生活,可能身边的每一样东西都需要连入全球因特网。在这种网络空间匮乏的环境下,IPv6 应运而生。它的产生不但解决了网络地址资源数量的问题,同时也为除电脑外的设备连入互联网在数量限制上扫清了障碍。

如果说 IPv4 实现的只是人机对话,那么 IPv6 则扩展到任意事物之间的对话,它不仅可以为人类服务,还将服务于众多硬件设备,如家用电器、传感器、远程照相机、汽车等,它将是无时不在,无处不在的深入社会每个角落的真正的宽带网,它所带来的经济效益也将非常巨大。

当然,IPv6 并非十全十美、一劳永逸,不可能解决所有问题。IPv6 只能在发展中不断完善,也不可能在一夜之间发生,过渡需要时间和成本,但从长远看,IPv6 有利于互联网的持续和长久发展。目前,国际互联网组织已经决定成立两个专门工作组,制定相应的国际标准。

4、Java 对 IPv6 的支持

随着 IPv6 越来越受到业界的重视,Java 从 1.4 版开始支持 Linux 和 Solaris 平台上的 IPv6。1.5 版起又加入了 Windows 平台上的支持。

相对于 C++,Java 很好得封装了 IPv4 和 IPv6 的变化部分,遗留代码都可以原生支持 IPv6,而不用随底层具体实现的变化而变化。

那么 Java 是如何来支持 IPv6 的呢?

Java 网络栈会优先检查底层系统是否支持 IPv6,以及采用的何种 IP 栈系统。如果是双栈系统,那它直接创建一个 IPv6 套接字(如图 1)。

图 1 - 双栈结构:

对于分隔栈系统,Java 则创建 IPv4/v6 两个套接字(如图 2):

  • 1)如果是 TCP 客户端程序:一旦其中某个套接字连接成功,另一个套接字就会被关闭,这个套接字连接使用的 IP 协议类型也就此被固定下来;
  • 2)如果是 TCP 服务器端程序:因为无法预期客户端使用的 IP 协议,所以 IPv4/v6 两个套接字会被一直保留;
  • 3)对于 UDP 应用程序:无论是客户端还是服务器端程序,两个套接字都会保留来完成通信。

图 2 - 分隔栈结构:

5、如何验证 IPv6 地址

5.1 IPv6 地址表示

从 IPv4 到 IPv6 最显著的变化就是网络地址的长度,IPv6 地址为 128 位长度,一般采用 32 个十六进制数,但通常写做 8 组每组 4 个十六进制的形式。

IPv6地址组成如下图所示:

▲ 本图引用自《 网络编程懒人入门(十一):一文读懂什么是IPv6 》

例如:

  • 1)2001:0db8:85a3:08d3:1319:8a2e:0370:7344 是一个合法的 IPv6 地址。如果四个数字都是零,则可以被省略;
  • 2)2001:0db8:85a3:0000:1319:8a2e:0370:7344 等同于 2001:0db8:85a3::1319:8a2e:0370:7344。

遵从这些规则,如果因为省略而出现了两个以上的冒号的话,可以压缩为一个,但这种零压缩在地址中只能出现一次。

因此:

2001:0DB8:0000:0000:0000:0000:1428:57ab 2001:0DB8:0000:0000:0000::1428:57ab 2001:0DB8:0:0:0:0:1428:57ab 2001:0DB8:0::0:1428:57ab 2001:0DB8::1428:57ab

都是合法的地址,并且他们是等价的。但 2001::25de::cade 是非法的(因为这样会使得搞不清楚每个压缩中有几个全零的分组)。同时前导的零可以省略,因此: 2001:0DB8:02de::0e13 等于 2001: DB8:2de::e13 。

5.2 IPv6 地址校验

IPv4 地址可以很容易的转化为 IPv6 格式。

举例来说:如果 IPv4 的一个地址为 135.75.43.52 (十六进制为 0x874B2B34 ),它可以被转化为 0000:0000:0000:0000:0000:0000:874B:2B34 或者::874B:2B34。同时,还可以使用混合符号(IPv4- compatible address),则地址可以为: :135.75.43.52 。

在 IPv6 的环境下开发 Java 应用,或者移植已有的 IPv4 环境下开发的 Java 应用到 IPv6 环境中来,对于 IPv6 网络地址的验证是必须的步骤,尤其是对那些提供了 UI(用户接口)的 Java 应用。

所幸的是:从 Java 1.5 开始,Java就增加了对 IPv6 网络地址校验的支持。程序员可以通过简单地调用方法 sun.net.util.IPAddressUtil.isIPv6LiteralAddress() 来验证一个 String 类型的输入是否是一个合法的 IPv6 网络地址。

为了更深入一步地了解 IPv6 的网络地址规范,及其验证算法,笔者参阅了一些材料,包括上文所述的方法 sun.net.util.IPAddressUtil.isIPv6LiteralAddress() 的源代码,以及目前网络上流传的一些 IPv6 网络地址的正则表达式,发现:

  • 1)由于 IPv6 协议所允许的网络地址格式较多,规范较宽松(例如零压缩地址,IPv4 映射地址等),所以导致了 IPv6 网络地址的格式变化很大;
  • 2)Java 对于 IPv6 网络地址的验证是通过对输入字符的循环匹配做到的,并没有采取正则表达式的做法。其匹配过程中还依赖于其它的 Java 方法;
  • 3)目前网络上流传的 IPv6 网络地址验证的正则表达式通常都只能涵盖部分地址格式,而且表达式冗长难读,非常不易于理解。

基于通用性考虑,以及为了使验证方法尽量简单易读,笔者尝试将 IPv6 网络地址的格式简单分类以后,使用多个正则表达式进行验证。

这种做法兼顾了通用性(基于正则表达式,所以方便用各种不同的编程语言进行实现),以及易读性(每个独立的正则表达式相对简短);并且根据测试,支持目前所有的 IPv6 网络地址格式类型,尚未发现例外。

以下是笔者用 Java 编写的对于 IPv6 网络地址的验证方法。此算法可被简单地用其它编程语言仿照重写。

演示代码1 - 验证地址:

//IPv6 address validator matches these IPv6 formats //::ffff:21:7.8.9.221 | 2001:0db8:85a3:08d3:1319:8a2e:0370:7344 //| ::8a2e:0:0370:7344 | 2001:0db8:85a3:08d3:1319:8a2e:100.22.44.55 //| 2001:0db8::8a2e:100.22.44.55 | ::100.22.44.55 | ffff:: //And such addresses are invalid //::8a2e:0:0370:7344.4 | 2001:idb8::111:7.8.9.111 | 2001::100.a2.44.55 //| :2001::100.22.44.55 public static boolean isIPV6Format(String ip) {     ip = ip.trim();     //in many cases such as URLs, IPv6 addresses are wrapped by []     if(ip.substring(0, 1).equals("[") && ip.substring(ip.length()-1).equals("]"))         ip = ip.substring(1, ip.length()-1);         return(1< Pattern.compile(":").split(ip).length)         //a valid IPv6 address should contains no less than 1,         //and no more than 7 ":” as separators             && (Pattern.compile(":").split(ip).length <= 8)         //the address can be compressed, but "::” can appear only once             && (Pattern.compile("::").split(ip).length <= 2)         //if a compressed address             && (Pattern.compile("::").split(ip).length == 2)             //if starts with "::” – leading zeros are compressed             ? (((ip.substring(0, 2).equals("::"))             ? Pattern.matches("^::([\\da-f]{1,4}(:)){0,4}(([\\da-f]{1,4}(:)[\\da-f]{1,4})         |([\\da-f]{1,4})|((\\d{1,3}.){3}\\d{1,3}))", ip)                 : Pattern.matches("^([\\da-f]{1,4}(:|::)){1,5}         (([\\da-f]{1,4}(:|::)[\\da-f]{1,4})|([\\da-f]{1,4})         |((\\d{1,3}.){3}\\d{1,3}))", ip)))         //if ends with "::" - ending zeros are compressed                 : ((ip.substring(ip.length()-2).equals("::"))                 ? Pattern.matches("^([\\da-f]{1,4}(:|::)){1,7}", ip)                 : Pattern.matches("^([\\da-f]{1,4}:){6}(([\\da-f]{1,4}         :[\\da-f]{1,4})|((\\d{1,3}.){3}\\d{1,3}))", ip));     }}

6、如何正规化 IPv6 地址

在网络程序开发中,经常使用 IP 地址来标识一个主机,例如记录终端用户的访问记录等。由于 IPv6 具有有零压缩地址等多种表示形式,因此直接使用 IPv6 地址作为标示符,可能会带来一些问题。

为了避免这些问题,在使用 IPv6 地址之前,有必要将其正规化。

除了通过我们熟知的正则表达式,笔者在开发过程中发现使用一个简单的 Java API 也可以达到相同的效果。

演示代码2 - 正规化地址:

InetAddress inetAddr = InetAddress.getByName(ipAddr); ipAddr = inetAddr.getHostAddress(); System.out.println(ipAddr);

InetAddress.getByName(String) 方法接受的参数既可以是一个主机名,也可以是一个 IP 地址字符串。

我们输入任一信息的合法 IPv6 地址,再通过 getHostAddress() 方法取出主机 IP 时,地址字符串 ipAddr 已经被转换为完整形式。

例如输入 2002:97b:e7aa::97b:e7aa ,上述代码执行过后,零压缩部分将被还原,ipAddr 变为 2002:97b:e7aa:0:0:0:97b:e7aa 。

7、如何获取本机 IPv6 地址

有时为了能够注册 listener,开发人员需要使用本机的 IPv6 地址,这一地址不能简单得通过 InetAddress . getLocalhost() 获得。因为这样有可能获得诸如 0:0:0:0:0:0:0:1 这样的特殊地址。使用这样的地址,其他服务器将无法把通知发送到本机上,因此必须先进行过滤,选出确实可用的地址。以下代码实现了这一功能,思路是遍历网络接口的各个地址,直至找到符合要求的地址。

演示代码3 - 获取本机 IP 地址:

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 instanceofInet6Address                 && !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;  * Check if it's "local address" or "link local address" or "loopbackaddress"  * @param ip address  * @return result private static boolean isReservedAddr(InetAddress inetAddr) {     if(inetAddr.isAnyLocalAddress() || inetAddr.isLinkLocalAddress()         || inetAddr.isLoopbackAddress()) {         return true;

 
推荐文章
腼腆的小摩托  ·  CCTV.com-台湾男歌手张震岳:地球人都知道我不吸毒(图)
7 月前
逼格高的蜡烛  ·  花样青春:非洲篇_百度百科
8 月前
爱听歌的鞭炮  ·  世界唯一以长寿为特色的景区,期颐老人遍布,最长寿的活了800岁_ ...
1 年前
奔放的松树  ·  2022天津外国语大学录取分数线(含2020-2021历年)_大学生必备网
1 年前
悲伤的鸭蛋  ·  天才在疯子左右正版包邮天才在左疯子在右高铭著(完整版)+你的善良 ...
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
小百科 - 百科知识指南
© 2024 ~ 沪ICP备11025650号