快速比较IP地址的最佳方法

时间:2014-06-29 18:03:49

标签: android algorithm ip-address

我正在解析两个包含IP地址的CSV文件。 第一个是源CSV,第二个是“黑名单”。

由于源文件的大小,我正在尝试优化找到与黑名单匹配的IP地址的速度。

编辑:黑名单由IP地址“块”组成。这意味着黑名单中的每条记录都有两个IP地址:一个Start块(例如216.254.128.0)和一个End块。 (例如,216.254.223.255)

这意味着直接查找等不起作用。

我想知道解决这个问题的最佳方法是什么。蛮力方法是:

String[] parts = sourceIP.split("\\."); // String array, each element is text between dots

int hi = 255;
int lo = 0;

int mid = (hi - lo) / 2 ;

if (Integer.valueOf(parts[0]) > mid) {
    mid = lo;
}

然后,我可以为每个part重复此操作,以确定IP地址是否在黑名单中。

这看起来相当激进,有4k +记录,这可能需要非常长的时间。

可能需要10多次迭代来决定每个部分,然后必须重复这些迭代以检查黑名单中IP块的“高”部分。这是每条记录80多次迭代。

我希望在这里获得一些输入,以查看比较IP地址的最佳方法。

你有什么想法?

是否可以使用快速按位掩码通过序列化INetAddress来快速比较值?

文件结构澄清:

源IP文件:

包含数据库中的记录列表。 (Aprox 4k)。每条记录都包含姓名,地址,电子邮件和IP地址。

黑名单:

包含4.2k记录。每条记录都是一个IP地址“块”。这包括两个IP地址。 1.开始和2.结束。

如果源列表中的记录具有在黑名单中找到的IP地址,我需要保存该记录并将其添加到新文件中。

5 个答案:

答案 0 :(得分:4)

我假设您正在谈论xxx.xxx.xxx.xxx格式的IPV4地址。

您可以轻松地将IP地址转换为整数。每个段(即xxx)是8位(即一个字节)。因此,它们中的四个一起构成一个32位整数。因此,给定类似" 192.168.100.12"的IP地址,您可以将其拆分为四个部分,将每个部分解析为一个字节并创建一个整数。例如,假设您创建了段的字节数组:

ipBytes[0] = 192;
ipBytes[1] = 168;
ipBytes[2] = 100;
ipBytes[3] = 12;

您可以将其转换为整数:

int ipAddress = ipBytes[0];
ipAddress = (ipAddress << 8) | ipBytes[1];
ipAddress = (ipAddress << 8) | ipBytes[2];
ipAddress = (ipAddress << 8) | ipBytes[3];

有更有效的方法可以做到这一点,但你明白了。您的语言的运行时库可能已经包含了解析IP地址并为您提供字节以使其成为整数的内容。

您有一组要检查源地址的IP地址范围。将每个范围加载到如下结构中:

class IPRange
{
    public int startIp;
    public int stopIp;
}

并将它们存储在数组或列表中。然后通过启动IP地址对列表进行排序。

对于每个源IP地址,将其转换为整数并对列表进行二进制搜索,搜索起始IP地址。源地址本身可能不会(可能不会被找到),但是当二进制搜索终止时,mid值将保留其起始IP地址小于或等于源的范围的索引地址。然后,您只需根据该项目的结束IP地址检查源地址,看它是否在该范围内。

二进制搜索是O(log n)。如果您正在搜索4,300个范围的列表,那么它最多需要13个探测器来查找阵列中的地址。即使在进行4,000次不同的搜索时,这应该足够快。您只是在讨论范围数组的50,000个探测器的顺序。

几点说明:

首先,正如我上面所说,我假设你在谈论IPV4地址。如果您正在谈论IPV6地址,相同的概念仍然适用,但您需要64位整数。我对IPv6知之甚少,不知道如何将地址转换为64位整数。可能你应该依赖你的运行时库来获取地址字节。

第二:我认为范围不重叠。也就是说,你不会有类似的东西:

start range    end range
192.168.1.1    192.168.2.255
192.168.2.1    192.168.3.255

如果您有,那么IP地址可能属于这两个范围。您可能构建重叠范围,以允许地址通过裂缝。如果你有重叠范围,问题会变得有点复杂。

答案 1 :(得分:0)

将两个文件放在String中。使用split(&#34;,&#34;)拆分第一个字符串中的ip。循环通过获得的ips数组。对于每个ip在第二个字符串中搜索它,如blacklist.indexOf("," + ip + ",")但首先添加&#34;,&#34;在黑名单字符串的开头和结尾。

答案 2 :(得分:0)

蛮力。 将所有内容加载到ram中,没有理由不这样做。 将ips拆分为2d阵列。 {0:123123123123} 黑名单到3d数组。 现在你可以开始搜索整数了。 当你有匹配时比较下一节。 如果源值较高,则与END块相同的部分进行比较。 当您将匹配推送到新阵列并将其写入最后的文件时。 如果这需要更多的时间来运行,那么我就输入了这个,然后关闭你打开的色情片,因为你的ram已满并使用你的页面文件。

答案 3 :(得分:0)

您可以使用名为Bloom Filter的数据结构。这是相当有效的性能和存储方式。至于一个例子,这里有一个问题,Most Efficient way of implementing a BlackList有一个建议的答案。

据我所知,谷歌Chrome也使用了这种技术,并且在 Matthials Vallentine的博客文章A Garden Variety of Bloom Filters中也得到了很好的解释。

Adobe leaked credentials checker可以找到更简洁的解释。一些摘录

  

原始泄漏约为9.3GB未压缩,其中3.3GB是电子邮件   地址[...]这意味着数据可以容纳512MB(即232位)   内存并允许我们在恒定时间内执行查找[...] An   允许占用840MB的最佳布隆过滤器   几乎没有任何误报。

答案 4 :(得分:0)

似乎最方向的解决方案是使用interval tree来存储黑名单。然后检查IP是否与任何间隔相交。

您还可以考虑使用Trie / hashtable来获取间隔相同的快速查找。 IE:216.254.128.0到216.254.223.255可以合并到216.254。(128.0,223.255),其中()是间隔。因此,您最终会得到两个哈希表查找(一个用于216,一个用于254),然后在区间树中搜索,这可能只包含少量元素。

您还可以将重叠间隔合并到一个间隔中,这可以在构建间隔树时完成。在这种情况下,最终更像是二叉搜索树。