浅谈IP黑名单高效设置与查询
IP黑名单设置与查询
- 按照最普通的思路,我们设置一个boolean类型的数组,将IP地址映射到本地内存中,也就是为每一个IP地址分配一个boolean数组的一个下标,用来表示该IP在不在黑名单中。由于IPv4中共有2^ 32个IP地址,因此共需要4GB内存用来存放boolean类型的数组。我们可以想到,用一个二进制位来表示一个IP地址在不在黑名单中,这样我们可以将内存减少为原来的1 / 8。我们只需要用一个512MB的数组即可为IPv4中的所有IP地址分配一个二进制位。通过 IP / 8来获取IP的状态映射到的字节,通过IP % 8来获取IP的状态映射在在这个字节的哪一位。
public class IpBlack {
private static byte[] ip = new byte[1 << 29]; // IP地址映射到本地内存数据的数组,用每个字节中的每一个位表示一个IP地址是不是在黑名单中,也就是说2的32次方个IP地址可以映射到2的32次方个位上,也就是2的29次方个字节上
private Byte mask = new Byte("11111111"); // 用来做异或运算
// 通过IP >> 3 (IP / 8) 来计算该IP地址对应的字节,通过IP & 7 (IP % 8)来计算该IP地址在对应某个字节中的位置
boolean isBlack(long input) {
// 查询本地内存数组中,第IP / 8 个字节中第IP % 8个位是否为1,这代表了这个IP地址是否在黑名单中
return (ip[(int)(input >> 3)] & (1 << (input & 7))) == 1 ? true : false;
}
void setBlack(long input, boolean isBlack) {
int byteIndex = (int)(input >> 3);
byte idx = (byte)(1 << (input & 7));
if(isBlack) {
// 将数组中对应字节对应位的二进制变为1
ip[byteIndex] = (byte)(ip[byteIndex] | idx);
} else {
// 将数组中对应字节对应位的二进制变为0
ip[byteIndex] = (byte)(ip[byteIndex] & (idx ^ mask));
}
}
}
时间并不会因为你的迷茫和迟疑而停留,就在你看这篇文章的同时,不知道有多少人在冥思苦想,在为算法废寝忘食,不知道有多少人在狂热地拍着代码,不知道又有多少提交一遍又一遍地刷新着OJ的status页面……
没有谁生来就是神牛,而千里之行,始于足下!