浅谈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));
        }
    }

}
posted @ 2021-04-15 22:11  Cruel_King  阅读(757)  评论(0编辑  收藏  举报