java ip to long_Java实现 IPv6 与 long 相互转换-Go语言中文社区

缘起

之前写了一篇《ip 地址与 int 整数的相互转换》,公众号 Java面试那些事转发了,有读者评论问到 IPv6 的转换方法,于是抽时间也自己实现了一下。

dd2487877020430c79b85172f2dc034e.png

IPv6 定义

IPv6是英文“Internet Protocol Version 6”(互联网协议第6版)的缩写,是互联网工程任务组(IETF)设计的用于替代IPv4的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址。IPv6的地址长度为128位,它有3种表示方法,分别是冒分十六进制表示法、0位压缩表示法、内嵌IPv4地址表示法。

分析

首先,IPv6 的地址长度为 128 位,而 Java 中没有 128 位的原生数字,int 为 32 位,long 是 64 位,因此若要将 IPv6 地址直接转为 long, 则会丢掉一半的信息,这肯定是不能接受的。

因此,解决方式有两种思路。第一,使用 BigInteger;第二,将 IPv6 地址的 128 位拆分为两个 64 位的地址,即可存到两个 long 整数组成的数组中。本文采用后者,即将 IPv6 地址转换为 long 数组。

代码实现

另外,为简便起见,我们只考虑冒分十六进制表示法的情况,即完整的ip地址,如 0:0:0:0:0:0:0:0,0位压缩表示法和内嵌 IPv4 地址表示法暂不考虑。

将 IPv6 地址转为 long 数组

/**

* 将 IPv6 地址转为 long 数组,只支持冒分十六进制表示法

*/

public static long[] ip2Longs(String ipString) {

if (ipString == null || ipString.isEmpty()) {

throw new IllegalArgumentException("ipString cannot be null.");

}

String[] ipSlices = ipString.split(":");

if (ipSlices.length != 8) {

throw new IllegalArgumentException(ipString + " is not an ipv6 address.");

}

long[] ipv6 = new long[2];

for (int i = 0; i < 8; i++) {

String slice = ipSlices[i];

// 以 16 进制解析

long num = Long.parseLong(slice, 16);

// 每组 16 位

long right = num << (16 * i);

// 每个 long 保存四组,i >> 2 = i / 4

ipv6[i >> 2] |= right;

}

return ipv6;

}

将 long 数组转为 IPv6 地址

/**

* 将 long 数组转为冒分十六进制表示法的 IPv6 地址

*/

public static String longs2Ip(long[] numbers) {

if (numbers == null || numbers.length != 2) {

throw new IllegalArgumentException(Arrays.toString(numbers) + " is not an IPv6 address.");

}

StringBuilder sb = new StringBuilder(32);

for (long numSlice : numbers) {

// 每个 long 保存四组

for (int j = 0; j < 4; j++) {

// 取最后 16 位

long current = numSlice & 0xFFFF;

sb.append(Long.toString(current, 16)).append(":");

// 右移 16 位,即去除掉已经处理过的 16 位

numSlice >>= 16;

}

}

// 去掉最后的 :

return sb.substring(0, sb.length() - 1);

}

测试一下

public static void main(String[] args) {

String[] ips4Test = new String[]{"FFFF:FFFF:7654:FEDA:1245:BA98:3210:4562",

"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "7654:0:FFFF:7654:562:222:7622:0", "0:0:0:0:0:0:0:0"};

for (String testCase : ips4Test) {

test(testCase);

}

}

private static void test(String testCase) {

long[] ipv6 = ip2Longs(testCase);

String ipString = longs2Ip(ipv6);

boolean eq = testCase.equalsIgnoreCase(ipString);

System.out.println("本次测试 ipv6 地址: " + testCase + ", 转为 long 数组: " + Arrays.toString(ipv6)

+ ", 再转回 ipv6 字符串: " + ipString + ", 是否与原字符串相等: " + eq);

if (!eq) {

throw new IllegalStateException("本次测试未通过!testCase: " + testCase);

}

}

输出结果:

本次测试 ipv6 地址: FFFF:FFFF:7654:FEDA:1245:BA98:3210:4562, 转为 long 数组: [-82623535708635137, 4999613583766065733], 再转回 ipv6 字符串: ffff:ffff:7654:feda:1245:ba98:3210:4562, 是否与原字符串相等: true

本次测试 ipv6 地址: FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF, 转为 long 数组: [-1, -1], 再转回 ipv6 字符串: ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, 是否与原字符串相等: true

本次测试 ipv6 地址: 7654:0:FFFF:7654:562:222:7622:0, 转为 long 数组: [8526721465200965204, 129888436749666], 再转回 ipv6 字符串: 7654:0:ffff:7654:562:222:7622:0, 是否与原字符串相等: true

本次测试 ipv6 地址: 0:0:0:0:0:0:0:0, 转为 long 数组: [0, 0], 再转回 ipv6 字符串: 0:0:0:0:0:0:0:0, 是否与原字符串相等: true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值