前段时间有以需求你,为了实现高效率的地址查找以及比对,将ip地址转化为long型存入redis进行处理,并按照ip进行AB(根据ip的奇偶)对照。
然后先梳理一下转换的逻辑和一些基础知识。
/**
* 之前存储ip都是存字符串,没想过ip地址竟然还能存Long,于是测试了一下确实可以。
* 举个简单例子先,比如有个ip地址是169.254.85.85,
* 对应的二进制是10101001.11111110.1010101.1010101,将小数点去掉后变为101010011111111010101011010101,
* 可以看到除了最低的位置的整数位置没有发生变化,其他三个位置的整数分别相对原来的位置左移了8位,16位,24位,而在二进制中每左移一位,就相当于*2,
* 也就是说对应的每段数字分别乘2的8次方,16次方以及24次方,总体来说思路就是去掉ip地址的小数点后重新计算,
* 上面这个ip地址转化为long型整数是2852017493,
* 当然如果你觉得这样计算比较麻烦也可以通过将每段数字转化为十六进制后拼接,之后在计算器中直接转化为十进制效果是一样的,对应的十六进制是A9FE5555
*
*
* 基础运算知识:
* 运算符解释:
* (1)、“|”符号的含义就是将两个数字的二进制按右端对齐,只要有数字1就换1,当两个数字都是0才是0例如
* 示例:202(二进制:11001010)| 163(10100011)可以像下面这样看 == 235(11101011)
* 11001010
* 10100011
* 将有一的换成一,全是零的是零:11101011
*
* (2)、<< 这个位运算符号(左移运算),这两个都是位运算符号,实例如下:
* 示例:202(11001010)<<2 == 808(1100101000) 表示202的二进制数字在右端添加两个零所表示的数字
*
* (3)、操作符为<<,向左移动,右边的低位补0,高位的就舍弃掉了,将二进制看做整数,左移1位就相当于乘以2。
* (4)、无符号右移:操作符为>>>,向右移动,右边的舍弃掉,左边补0。
* (5)、有符号右移:操作符为>>,向右移动,右边的舍弃掉,左边补什么取决于原来最高位是什么,原来是1就补1,原来是0就补0,将二进制看做整数,右移1位相当于除以2。
*
*/
1、ip地址转long型
private static Long ipToLong(String ipStr) {
long ipLong = 0;
if (ipStr != null && ipStr.length() > 0) {
//将ip(点分十进制的形式 a.b.c.d) 地址按.分割
String[] ipSplit = ipStr.split("\\.");
try {
if (ipSplit.length != 4) {
throw new Exception("IP Format Error");
}
for (int i = 0; i < ipSplit.length; i++) {
int temp = Integer.parseInt(ipSplit[i]);
ipLong += temp * (1L << (ipSplit.length - i - 1) * 8);
}
} catch (Exception e) {
log.error("ip address to long type Error :{}", e);
}
} else {
log.info("ip address is null or is ''");
}
return ipLong;
}
2、long型ip转点分十进制格式
/**
* 将long型IP地址转换回点分十进制表示的字符串类型
* @param ipLong
* @return java.lang.String
* @throws Exception
*/
private static String ipLongToString(long ipLong) {
StringBuffer ipStr = new StringBuffer();
try {
if (ipLong < 0) {
throw new Exception("Can not to IP...");
}
//最高8位,直接右移24位
ipStr.append((ipLong >>> 24));
ipStr.append(".");
//将高8位设置0,然后右移16位
ipStr.append(((ipLong & 0x00FFFFFF) >>> 16));//获得高8位,6个f对应的是24个1,最高8位设置空为0,之后右移16位将前面多余的16位去掉,以下类推即可
ipStr.append(".");
//将高16位设置0,然后右移8位
ipStr.append((ipLong & 0x0000FFFF) >>> 8); //前16位 设置0,移除低8位,16个1,高16位设置为0
ipStr.append(".");
//将高24位设置0
ipStr.append(ipLong & 0x000000FF); //前24位 设置0,留低8位,8个1,高24位设置为0
} catch (Exception e) {
log.error("Long type ip to point ten type error :{}", e);
}
return ipStr.toString();
}
测试结果: