使用int来存储ip地址
上次在面试的时候面试官问了我一个比较有意思的问题,如何用一个int来存储一个IP地址。面试官竟然问了,那么就有他的一个可行性,于是,我就开始整理我的思绪。
现在的ipv4是点分十进制的,比如,1129.168.255.25,转化为二进制为10000001101010001111111100011001。一共32位,刚好一个int也是32位,我们可以将ip地址进行一个处理,转化为二进制,然后一位位的存储在int的每一位中,不就可以了吗。于是,我开始了我的编码。
public class ipByint {
//主函数
public static void main(String[] args) {
String ip = "129.168.255.25";
String binaryString=bytetoint(getByte(ip));
System.out.println("ip转化为二进制:"+binaryString);
System.out.println("这里是int的最大值:"+Integer.MAX_VALUE);
}
//将ip处理存储在Byte数组中
public static Byte[] getByte(String ip) {
Byte[] arrs = new Byte[4];
String[] ipaddStrings = ip.split("\\.");
arrs[0] = (byte) Integer.parseInt(ipaddStrings[0]);
arrs[1] = (byte) Integer.parseInt(ipaddStrings[1]);
arrs[2] = (byte) Integer.parseInt(ipaddStrings[2]);
arrs[3] = (byte) Integer.parseInt(ipaddStrings[3]);
//System.out.println(arrs[0]);
return arrs;
}
//将Byte数组的十进制数字转化为二进制,拼接成一个32位二进制字符串
public static String bytetoint(Byte[] arrs) {
StringBuffer stringBuffer=new StringBuffer();
for (int i = 0; i < arrs.length; i++) {
String s=Integer.toBinaryString(arrs[i]&0xFF);
int length=s.length();
if (length<8) {
for (int j = 0; j < 8-length; j++) {
s="0"+s;
}
}
stringBuffer.append(s);
}
return stringBuffer.toString();
}
//二进制转化为十进制
public static int binary2ten(String s) {
return Integer.parseInt(s,2);
}
}
这是我大概的代码,运行结果如下。
这里我们对ip地址字符串进行了一个处理,将十进制的ip地址转化为了32位的二进制,可是当我将这一串二进制数字存入int的时候,却报错了。
经过检查发现这个二进制转化为为十进制的数字为2175336217,而int的十进制范围为-2147483648~+2147483647。很明显ip转化的这个数字明显比
int的上限高一点,所以出现了范围的错误。
对于以上情况,我暂时有两种方案
第一种,使用无符号的int,无负号的int的范围为0~4294967295。我们发现这个数字高达42亿,能够满足所有的IP地址的存储了
(java不支持无符号啦,当然这只是一个思路,我们可以用其他的一个语言进行编码)
第二种稍微复杂一点,我们先来看看jvm是怎么来处理这个问题的,我们知道byte的范围是-128-127,可byte怎么来存储一个大于127小于255的数字呢。
我们来看看运行结果。
我们的IP地址为129.168.255.25,我们发现有三位数字都大于127,他们被jvm处理变成了一个负数来进行表示,我们来看看他是怎么做到的。
129 的原码为 1000 0001
129的反码为 1111 1110 原码变反码,首位符号为0为正,1为负数。其他位取反
129的补码为 1111 1111 补码就是原码加1
由于第一位是符号为,故补码的十进制为-127
168的源码为 1010 1000
168的反码为 1101 0111
168的补码为 1101 1000
补码的十进制为-88
255的原码为1111 1111
255的反码为1000 0000
255的补码为1000 0001
补码的十进制为-1
因此,我们的int范围超了。我们可以转化为补码进行一个存储,当需要逆向的时候的,我们就可以补码转原码,原码转成十进制之后进行一个处理,这样我们就可以从
一个32位补码到原码到转化为十进制,变成一个字符串的ip了。
下面讲解如何补码到原码,比如刚刚的255的补码为1000 0001
255的补码为1000 0001
反码一次,第一位符号为不变1111 0001
加1 1111 1111
原码就为1111 1111,十进制的数字为255.
这样我们就完成了一个补码到原码的逆向操作了