IP地址(IPV4)与int类型之间的转换

IP地址(IPV4)与int类型之间的转换


  1. IP地址(IPV4)与int类型之间的转换
  2. IP地址(IPV6)与long数组之间的转换

一、前言

IP地址(IPV4)是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址(IPV4)通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)。

即ip 地址(IPV4)本身就是一个32位的二进制数,只是通常被以 a.b.c.d 的形式表示而已。

二、IP地址(IPV4)为什么要转换为int类型

根据前言,我们知道IP地址(IPV4)分为四段,每段都是 0~255 之间的数,每段可以用 8 位来装下它,4x8=32位,也就是可以将ip地址转为 32 位的整数。而Java中的int类型正好是32位。

那么为什么要将 IP地址(IPV4)转为数字呢?其实就是时间换空间的一种方式。如果把IP地址(IPV4)用String类型表示的话,那么会占用 7 (如0.0.0.0) 到 15 (如 255.255.255.255) 个字节,而用 int 类型表示的话只需要 4 个字节!

三、IP地址(IPV4)与int类型之间的相互转换

1.IP地址(IPV4)转换为int类型

/**
 * 将IP地址(IPV4)字符串转换为 int类型的数字
 * 
 * 思路:将 IP地址(IPV4)的每一段数字转为 8 位二进制数,并将它们放在结果的适当位置上
 *
 * @param IP地址(IPV4) 字符串,如 127.0.0.1
 * @return IP地址(IPV4)  字符串对应的 int值
 */
public static int ipv4ToInt(String ipv4_string) {
	// 取 ip 的各段
    String[] ipSlices = ipv4_string.split("\\.");
    
    int result = 0;
    
    for (int i = 0; i < ipSlices.length; i++) {
        // 将 ip 的每一段解析为 int,并根据位置左移 8 位
        int intSlice = Integer.parseInt(ipSlices[i]) << 8 * i;
        
        // 求或
        result = result | intSlice;
    }
    
    return result;
}

以 255.255.255.255 这个地址为例,上面的或运算过程如下。

result的初始值为0

与第四段的255进行或运算
00000000 00000000 00000000 00000000
00000000 00000000 00000000 11111111

与第三段的255进行或运算
00000000 00000000 00000000 11111111
00000000 00000000 11111111 00000000

与第二段的255进行或运算
00000000 00000000 11111111 11111111
00000000 11111111 00000000 00000000

与第一段的255进行或运算
00000000 11111111 11111111 11111111
11111111 00000000 00000000 00000000

最终结果
11111111 11111111 11111111 11111111

注意: 原码11111111 11111111 11111111 11111111是个负数,对应的反码为10000000 00000000 00000000 00000000,对应的补码为10000000 00000000 00000000 00000001,即-1。所以255.255.255.255的转为int的值是-1。

2.int类型转换为IP地址(IPV4)

/**
 * 将 int类型的数字转换为IP地址(IPV4)字符串
 *
 * @param ipv4_int 用 int表示的IP地址(IPV4)字符串
 * @return IP地址(IPV4)字符串,如 127.0.0.1
 */
public static String intToIpv4(int ipv4_int) {
	String[] ipString = new String[4];

    for (int i = 0; i < 4; i++) {
        // 每 8 位为一段,这里取当前要处理的最高位的位置
        int pos = i * 8;
        
        // 取当前处理的 ip 段的值
        int and = ipv4_int & (255 << pos);
        
        // 将当前 ip 段转换为 0 ~ 255 的数字,注意这里必须使用无符号右移
        ipString[i] = String.valueOf(and >>> pos);
    }
    
    return String.join(".", ipString);
}

以 -1这个int为例,上面的无符号右移运算过程如下。

-1的原码为11111111 11111111 11111111 11111111

当i=0时,pos=0
and = ipv4_int &(255 << pos)
进行与运算
11111111 11111111 11111111 11111111
00000000 00000000 00000000 11111111
结果为
00000000 00000000 00000000 11111111
and >>> pos
进行无符号右移0位运算,结果为255

当i=1时,pos=8
and = ipv4_int &(255 << pos)
进行与运算
11111111 11111111 11111111 11111111
00000000 00000000 11111111 00000000
结果为
00000000 00000000 11111111 00000000
and >>> pos
进行无符号右移8位运算,结果为255

当i=2时,pos=16
and = ipv4_int (255 << pos)
进行与运算
11111111 11111111 11111111 11111111
00000000 11111111 00000000 00000000
结果为
00000000 11111111 00000000 00000000
and >>> pos
进行无符号右移16位运算,结果为255

当i=3时,pos=24
and = ipv4_int &(255 << pos)
进行与运算
11111111 11111111 11111111 11111111
11111111 00000000 00000000 00000000
结果为
11111111 00000000 00000000 00000000
and >>> pos
进行无符号右移24位运算,结果为255

3.测试

public static void main(String[] args) {
	String ipv4_string = "255.255.255.255";
		
	int ipv4_int = ipv4ToInt(ipv4_string);
	System.out.println(ipv4_string + "对应的int值为:" + ipv4_int);

	System.out.println(ipv4_int + "对应的ip值为:" + intToIpv4(ipv4_int));
}

输出结果为:

255.255.255.255对应的int值为:-1

-1对应的ip值为:255.255.255.255

四、注意

1.使用无符号右移那句是要转为0到255的正整数,如果带符号右移,则左边会补1导致结果不对。
2.文中相互转换的算法是配套的,不同的转换算法计算的 int 值可能会不一样,因为虽然都是处理 ip 的 4 个部分,但是它们的结合顺序可以不一样,因此以怎样的顺序搭配转为 int,就应该以相同的顺序解析为 String。
3.直接保存字符串,虽然可读性最好,但浪费了不少的存储空间;转换后再存储,虽然节约了存储空间,但可读性较差。该如何取舍,还是根据具体的应用场景来决定。


参考:https://mp.weixin.qq.com/s/FzAMbks0PUorZFsCFw7KTg

©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页