Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中IP地址筛选器内存中数据结构的最佳选择_Java_Filter_Ip_In Memory - Fatal编程技术网

Java中IP地址筛选器内存中数据结构的最佳选择

Java中IP地址筛选器内存中数据结构的最佳选择,java,filter,ip,in-memory,Java,Filter,Ip,In Memory,我有一个CIDR格式的文件,像这样192.168.1.0/24,它被转换成两列结构 3232236030 3232235777 每个字符串IP地址转换都与以下代码一起发生: String subnet = "192.168.1.0/24"; SubnetUtils utils = new SubnetUtils(subnet); Inet4Address a = (Inet4Address) InetAddress.getByName(utils.getInfo().ge

我有一个CIDR格式的文件,像这样
192.168.1.0/24
,它被转换成两列结构

3232236030 3232235777
每个字符串IP地址转换都与以下代码一起发生:

String subnet = "192.168.1.0/24";
SubnetUtils utils = new SubnetUtils(subnet);

Inet4Address a = (Inet4Address) InetAddress.getByName(utils.getInfo().getHighAddress());
long high = bytesToLong(a.getAddress());
Inet4Address b = (Inet4Address) InetAddress.getByName(utils.getInfo().getLowAddress());
long low = bytesToLong(b.getAddress());

private static long bytesToLong(byte[] address) {
   long ipnum = 0;
   for (int i = 0; i < 4; ++i) {
       long y = address[i];
       if (y < 0) {
           y += 256;
       }
       ipnum += y << ((3 - i) * 8);
   }
   return ipnum;
}
String subnet=“192.168.1.0/24”;
SubnetUtils utils=新的SubnetUtils(子网);
Inet4Address a=(Inet4Address)InetAddress.getByName(utils.getInfo().getHighAddress());
long high=bytestolog(a.getAddress());
Inet4Address b=(Inet4Address)InetAddress.getByName(utils.getInfo().getLowAddress());
long low=bytestolog(b.getAddress());
专用静态长bytestolog(字节[]地址){
长ipnum=0;
对于(int i=0;i<4;++i){
长y=地址[i];
if(y<0){
y+=256;
}

ipnum+=y我将使用一个int排序数组(基址)和另一个大小相同的数组(结束地址)。这将使用5M*8=40 MB。第一个IP是基址,第二个IP是范围内的最后一个地址。您需要删除交点


若要查找某个地址是否被过滤为二进制搜索O(logn),若不是精确匹配,请检查它是否小于(或等于)上限。

这是答案的开头,我会在有更多空闲时间时返回

设置:

  • 按起始编号对范围进行排序
  • 由于这些是IP地址,我假设所有范围都不重叠。如果有重叠,您可能应该运行列表合并范围并修剪不必要的范围(例如,如果您有范围1-10,您可以修剪范围5-7)。
  • 要合并或修剪,请执行此操作(假设范围a紧跟在范围b之前):
  • 如果b.end
  • 如果b.starta.end,则可以合并范围a和b。设置a.end=b.end,然后删除范围b
  • 当涉及到它时,我只需要知道IP是否存在于5M范围内

    我会考虑一个n元树,其中n=256,从虚线地址而不是转换的整数中工作。< /P> 顶层是256个对象的数组。

    null
    条目表示“否”,没有包含地址的范围,因此在您的示例中,
    192.168.1.0/24
    array[192]将包含一个对象,但是array[100]可能为null,因为没有为任何100.x.x.x/n定义范围

    存储的对象包含(引用)另一个数组[256]和一个范围说明符,只设置其中一个,因此
    192.0.0.0/8
    将以一个范围说明符结束,该范围说明符指示要过滤该范围内的所有地址。这将允许像
    192.255.0.0/10
    这样的事情,其中地址的前10位是有效的
    1100 0000 11xx xxxx
    ——否则你需要检查二级数组中的下一个八位元

    最初将重叠范围(如果有)合并到更大的范围中…例如,
    3..10
    7..16
    变为
    3..16
    …允许这样做,因为您不需要将给定的IP与定义它的范围相关联

    这需要不超过8次比较。每个八位字节最初直接用作索引,然后是null比较,终端节点比较(是范围还是指向下一个树级别的指针)

    如果每个IP地址都在一个筛选范围内,最坏情况下的内存消耗理论上是4 GB
    (256^4)
    ,但当然这会合并到一个范围内,因此实际上只有一个范围对象。更现实的最坏情况可能更像
    (256^3)
    或16.7 MB。在实际使用中,每个级别上的大多数阵列[256]节点可能都是空的


    这本质上类似于哈夫曼/前缀编码。最短的不同前缀可以在找到答案(一个范围)后立即终止,因此您通常会得到
    <4
    比较的平均值。

    我在项目中发现了这种二进制切分算法:

    公共IpRange isInRange(长地址){
    检查重建();
    if(mergedRanges.length==0){
    返回(空);
    }
    //辅助二进制切分
    int-bottom=0;
    int top=mergedRanges.length-1;
    int电流=-1;
    while(顶部>=0&&bottom如果(top>=0&&bottom
    除非你过滤的是非常大的N个地址,否则这都是字符串比较,执行速度会非常快。你不需要基于高/低阶位和所有那些复杂的Jazz构建二叉树

    String subnet = "192.168.1.0/24";
    SubnetUtils utils = new SubnetUtils(subnet);
    //...
    //for each subnet, create a SubnetUtils object
    Set<SubnetUtils> subnets = getAllSubnets();
    //...
    
    String subnet=“192.168.1.0/24”;
    SubnetUtils utils=新的SubnetUtils(子网);
    //...
    //对于每个子网,创建SubnetUtils对象
    Set subnets=getAllSubnets();
    //...
    
    使用番石榴谓词筛选不在子网范围内的IP地址:

       Set<String> ipAddresses = getIpAddressesToFilter();
       Set<String> ipAddressesInRange = 
           Sets.filter(ipAddresses, filterIpsBySubnet(subnets))
    
    
       Predicate<String> filterIpsBySubnet(final Set<SubnetUtils> subnets){
           return new Predicate<String>() {
                @Override
                public boolean apply(String ipAddress) {
                    for (SubnetUtils subnet : subnets) {
                        if (subnet.getInfo().isInRange(ipAddress)) {
                            return true;
                        }
                    }
                    return false;
                }
            };
       }
    
    Set-ipaddress=getipaddress-stofilter();
    设置IPAddresssInRange=
    set.filter(IP地址、filterIpsBySubnet(子网))
    谓词过滤器子网(最终集子网){
    返回新谓词(){
    @凌驾
    公共布尔应用(字符串ipAddress){
    用于(子网UTILS子网:子网){
    if(subnet.getInfo().isInRange(ipAddress)){
    返回true;
    }
    }
    返回false;
    }
    };
    }
    
    现在,如果IP在任何子网中,你都有一个很好的简单过滤器,你不必构建一个需要单元测试的数据结构
       Set<String> ipAddresses = getIpAddressesToFilter();
       Set<String> ipAddressesInRange = 
           Sets.filter(ipAddresses, filterIpsBySubnet(subnets))
    
    
       Predicate<String> filterIpsBySubnet(final Set<SubnetUtils> subnets){
           return new Predicate<String>() {
                @Override
                public boolean apply(String ipAddress) {
                    for (SubnetUtils subnet : subnets) {
                        if (subnet.getInfo().isInRange(ipAddress)) {
                            return true;
                        }
                    }
                    return false;
                }
            };
       }