版權(quán)聲明:本文源自簡書tianma慨绳,轉(zhuǎn)載請務(wù)必注明出處: http://www.reibang.com/p/70185244e46c
問題分析
對于ipv4的地址來說悦屏,如果用字符串的形式存儲的話展融,其占用字節(jié)就比較大淳玩,比如對于IPv4地址0.0.0.0的字符串谆奥,就需要7個字節(jié)见坑,IPv4為255.255.255.255 的字符串粹污,需要15個字節(jié)段多,也就是說存儲一個ip需要占用7~15個字節(jié)。
那么有沒有更節(jié)省空間的存儲方式呢壮吩?答案是有进苍。
方案1: 直接把字符串中的'.'去掉,不就變成一個數(shù)字了嘛鸭叙,比如 "255.255.255.255" 變成 255255255255觉啊,然而我們知道int所能表示的最大值 = Integer.MAX_VALUE = 2^31-1 = 2147483647, 255255255255 > 2^31-1沈贝,所以需要用長整形long來表示杠人,長整形占用8個字節(jié),也就是說我們將7~15個字節(jié)轉(zhuǎn)換為8字節(jié)宋下,在絕大多數(shù)情況下是節(jié)省空間了的嗡善。
方案2: 因為考慮到IPv4的地址本質(zhì)上就是32位的二進制串,而一個int類型的數(shù)字剛好為4個字節(jié)32個bit位学歧,所以剛好可以用一個int類型的數(shù)字轉(zhuǎn)表示IPv4地址罩引。所以,我們可以用4個字節(jié)的int數(shù)字表示一個ip地址枝笨,這樣可以大大節(jié)省空間袁铐。
這里只討論方案2 :)
演示
對于ipv4地址: 192.168.1.3:
每段都用二進制表示: 192(10) = 11000000(2) ; 168(10) = 10101000(2) ; 1(10) = 00000001(2) ; 3(10) = 00000011(2) 。
所以連在一起就是:11000000101010000000000100000011横浑,對應(yīng)的int數(shù)字就是-1062731775 剔桨。
具體算法分析:
192左移24位: 11000000 00000000 00000000 00000000
168左移16位: 00000000 10101000 00000000 00000000
001左移08位: 00000000 00000000 00000001 00000000
003左移00位: 00000000 00000000 00000000 00000011
按位或結(jié)果???: 11000000 10101000 00000001 00000011
即 -1062731775
將int類型的數(shù)字轉(zhuǎn)換成ip地址,其實就是上述過程的逆過程伪嫁,這里就不再贅述领炫。
Java實現(xiàn)
/**
* IPv4地址和int數(shù)字的互相轉(zhuǎn)換
*
* @author Tianma
*
*/
public class IPv4IntTransformer {
/**
* IPv4地址轉(zhuǎn)換為int類型數(shù)字
*
*/
public static int ip2Integer(String ipv4Addr) {
// 判斷是否是ip格式的
if (!isIPv4Address(ipv4Addr))
throw new RuntimeException("Invalid ip address");
// 匹配數(shù)字
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(ipv4Addr);
int result = 0;
int counter = 0;
while (matcher.find()) {
int value = Integer.parseInt(matcher.group());
result = (value << 8 * (3 - counter++)) | result;
}
return result;
}
/**
* 判斷是否為ipv4地址
*
*/
private static boolean isIPv4Address(String ipv4Addr) {
String lower = "(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])"; // 0-255的數(shù)字
String regex = lower + "(\\." + lower + "){3}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(ipv4Addr);
return matcher.matches();
}
/**
* 將int數(shù)字轉(zhuǎn)換成ipv4地址
*
*/
public static String integer2Ip(int ip) {
StringBuilder sb = new StringBuilder();
int num = 0;
boolean needPoint = false; // 是否需要加入'.'
for (int i = 0; i < 4; i++) {
if (needPoint) {
sb.append('.');
}
needPoint = true;
int offset = 8 * (3 - i);
num = (ip >> offset) & 0xff;
sb.append(num);
}
return sb.toString();
}
}