你会如何比较IP地址?

时间:2008-10-02 03:28:37

标签: ip-address

对于我的服务器应用程序,我需要检查一个IP地址是否在我们的黑名单中。

比较IP地址的最有效方法是什么?将IP地址转换为整数并将它们比较有效吗?

13 个答案:

答案 0 :(得分:28)

取决于您正在使用的语言,但IP地址通常存储为32位无符号整数,至少在网络层存储,使得比较速度非常快。即使不是这样,除非您正在设计高性能分组交换应用程序,否则它不太可能成为性能瓶颈。避免过早优化 - 设计程序的可测试性和可伸缩性,如果遇到性能问题,可以使用分析器查看瓶颈所在。

编辑:为了澄清,IPv4地址存储为32位整数,加上网络掩码(IP地址比较不需要)。如果您使用的是较新的且当前更为罕见的IPv6,则地址将为128位长。

答案 1 :(得分:7)

32位整数是要走的路 - 直到你开始处理128位IPv6地址。

答案 2 :(得分:5)

你的意思是你应该将它作为文本字符串进行比较,还是将int转换为int并比较为int?

这通常不是这种查找的瓶颈。你可以尝试实现这两种方法,看看哪一种运行得更快。

IP地址查找的真正问题通常是进行有效的查询,利用您处理IP地址而不仅仅是随机数的事实。要完成此任务,您可以查找LC triethis article

显然,只有当您的黑名单中包含数万或数百万条目时,您才会感兴趣。如果它只有10-20个条目,则应首选线性搜索,实际上更有趣的问题是文本比较与整数比较。

答案 3 :(得分:5)

static public bool IsEqual(string ToCompare,
                                      string CompareAgainst)
  {

     return IPAddressToLongBackwards(ToCompare)==IPAddressToLongBackwards(CompareAgainst);
  }

static private uint IPAddressToLongBackwards(string IPAddr)
  {
     System.Net.IPAddress oIP=System.Net.IPAddress.Parse(IPAddr);
     byte[] byteIP=oIP.GetAddressBytes();


     uint ip=(uint)byteIP[0]<<24;
     ip+=(uint)byteIP[1]<<16;
     ip+=(uint)byteIP[2]<<8;
     ip+=(uint)byteIP[3];

     return ip;
  }

如果我理解正确,这是比较两个IP地址的代码。你想要这个吗?你可以进一步做这样的事情:

static public bool IsGreater(string ToCompare,
                               string CompareAgainst)
  {

     return IPAddressToLongBackwards(ToCompare)>
        IPAddressToLongBackwards(CompareAgainst);
  }

因为你得到了地址字节。

答案 4 :(得分:4)

是的,我发现效率很高,但它会很长,当然你必须以整数形式索引列入黑名单的IP。

答案 5 :(得分:3)

使用像PeerGuardian这样的工具,它允许驱动程序级别的传入TCP / IP连接到黑名单上的IP。高度安全,无需代码(可以说:高度安全,因为无需代码)。

答案 6 :(得分:3)

我已经完成了这个并且我已经测试了它,使用unsigned int(32位)是最快的 - 我假设你将它与字符串表示进行比较。

可能对你有帮助的另一件事是在创建表时,过去我有2个列:LowIP和HighIP;通过这种方式,我能够通过1个记录条目将整个IP范围列入黑名单,并通过检查范围内的IP来获得良好的性能。

答案 7 :(得分:3)

我曾经继承了代码,其中某人想到将IP地址存储为4个int是一件非常好的事情,除非他们把所有时间都花在转换为int的上面。

将它们保存为数据库中的字符串要容易得多,而且只需要一个索引。你会惊讶于sql server能够索引字符串而不是4列整数。但是这个IP列表不是用于黑名单。数据库往返是非常昂贵的。

如果数据库过度,则将它们存储在内存中的字典中,但这只是猜测,因为我们不知道您需要比较多少。由于大多数哈希码都是32位int,而IPv4地址是32位,因此IP地址本身可能只是一个很好的哈希码。

但正如其他人所指出的,最好的选择可能是减少服务器上的负载并购买专用硬件。也许你最近将黑名单的IP保留在内存中,并定期向路由器发布新的IP。

如果你是那个试图在路由器中制作软件的人,那么你需要掏出你的数据结构书并创建类似b树的东西。

答案 8 :(得分:3)

Radix或PATRICIA Trie是最佳结构。

查看流量工具的C源代码: http://www.splintered.net/sw/flow-tools/

我多年前就开始工作了。

答案 9 :(得分:2)

您是否存在效率问题?

如果是这样,那么一定要发布代码(或伪代码),我们可以选择尸体。

如果没有,那么我建议尝试一些简单的方法,例如将条目存储在排序列表中,并使用您现有的Sort()Find()环境。

答案 10 :(得分:2)

整数比较比字符串比较快得多。

如果将整数存储在已排序的列表中,则可以比未排序的列表更快地找到它们。

答案 11 :(得分:1)

如果您将IP地址作为字符串接收,将其与字符串进行比较可能比将其转换为整数表示更有效

但是,如果几毫秒(纳秒!)对此操作有影响,我会对这两种解决方案进行分析; - )

答案 12 :(得分:1)

以下是我在JavaScript中使用过的

function isValidIPv4Range(iPv4Range = '') {
  if (IP_V4_RANGE_REGEX.test(iPv4Range)) {
    const [fromIp, toIp] = iPv4Range.split('-');

    if (!isValidOctets(fromIp) || !isValidOctets(toIp)) {
      return false;
    }

    const convertToNumericWeight = ip => {
      const [octet1, octet2, octet3, octet4] = ip.split('.').map(parseInt);

      return octet4 + (octet3 * 256) + (octet2 * 256 * 256) + (octet1 * 256 * 256 * 256);
    };

    return convertToNumericWeight(fromIp) < convertToNumericWeight(toIp);
  }
  return false;
}