【问题标题】:Best way to compare IP addresses quickly快速比较 IP 地址的最佳方法
【发布时间】:2014-08-20 03:42:35
【问题描述】:

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

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

编辑:黑名单由 IP 地址“块”组成。这意味着黑名单中的每条记录都有两个 IP 地址:一个Start Block(例如 216.254.128.0)和一个End Block。 (例如 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文件:

包含来自数据库的记录列表。 (大约 4k)。每条记录都包含姓名、地址、电子邮件和 IP 地址。

黑名单:

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

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

【问题讨论】:

  • 我不明白这段代码的用途。
  • 我目前没有使用该代码。这是一种简单的整数搜索方法,用于“查找”值在数组中的位置。我会用它来查看该值是否存在(它在黑名单中的某处找到),或者您是否最终位于两条记录之间并且源 IP 地址也不匹配。如果是这种情况,则该 IP 地址不存在于黑名单中。正如我所说,这是一种相当蛮力的方法,我希望找到更好的解决方案。
  • 您有什么理由必须将这些 IP 存储在一个文件中?似乎有更好的方法来存储这么多记录
  • 黑名单有多大?如果它不是太大,只需将其加载到内存中,将 IP 地址转换为整数,然后排序。然后,您可以从源文件中加载每个地址,将其转换为整数,然后在黑名单上进行二进制搜索。或者,您可以从黑名单条目创建字典并进行直接查找。
  • 对 4.2K 记录进行二进制搜索将需要 最多 12 次探测。因此,您正在谈论总共 50,000 次查找,以检查您的所有记录。这将需要不到一秒钟的时间。从文件中读取源记录的时间比搜索要长。

标签: android algorithm ip-address


【解决方案1】:

我假设您说的是 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 地址可能属于这些范围中的任何一个。您可能会构建重叠范围,使地址从裂缝中消失。如果你有重叠的范围,问题会变得有点复杂。

【讨论】:

  • 哇,多么全面的答案。因此,我得出了几乎相同的结论,并且现在正在实施解决方案的 IPv6 部分。不过很好的答案。我很伤心,它是在我自己研究解决方案之后出现的。 XD。不过,为了子孙后代,这是要走的路。
【解决方案2】:

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

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

您还可以将重叠的区间合并为一个区间,这可能在您构建区间树时完成。在这种情况下,它最终更像是一棵二叉搜索树。

【讨论】:

    【解决方案3】:

    您可以使用名为Bloom Filter 的数据结构。这是相当有效的性能和存储明智的。举个例子,这里有一个问题,Most Efficient way of implementing a BlackList 有一个推荐这个的答案。

    据我所知,谷歌浏览器也使用了这种技术,Matthials Vallentine 的博文A Garden Variety of Bloom Filters也很好地解释了这一点。

    更简洁的解释可以在Adobe leaked credentials checker 找到。部分摘录

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 很遗憾,这行不通。无法直接查找,因为黑名单是一系列 IP“块”。我现在正在为问题添加更多信息。
        • 好的,但是您的额外信息还不够。至少对我来说不是。我不明白。只需从此类文件中发布相关部分以使其清楚。
        • 我不确定如何更清楚每个文件包含的内容。检查上面的新编辑。出于法律/隐私原因,我无法从文件中粘贴任何真实信息。
        猜你喜欢
        • 2016-01-07
        • 2010-12-29
        • 1970-01-01
        • 2021-01-10
        • 1970-01-01
        • 1970-01-01
        • 2015-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多