我们将如何比较IP地址?
对于我的服务器应用程序,我需要检查IP地址是否在我们的黑名单中。
比较IP地址最有效的方法是什么?将IP地址转换为整数并比较它们的效率吗?
解决方案
取决于我们使用的语言,但IP地址通常至少在网络层存储为32位无符号整数,从而使比较非常快。即使不是这样,除非我们正在设计一个高性能的数据包交换应用程序,否则它不太可能成为性能瓶颈。避免过早优化设计程序的可测试性和可伸缩性,如果遇到性能问题,则可以使用探查器查看瓶颈所在。
编辑:澄清一下,IPv4地址存储为32位整数,外加一个网络掩码(IP地址比较不需要)。如果我们使用的是较新的且当前更稀有的IPv6,则地址将为128位长。
是的,我发现这样做要有效,但是要花很长时间,当然我们必须以整数形式对列入黑名单的IP进行索引。
32位整数是可以使用的方法-直到我们开始处理128位IPv6地址。
使用PeerGuardian之类的工具禁止在驱动程序级别与黑名单上的IP的传入TCP / IP连接。高度安全,不需要代码(可以说:高度安全,因为不需要代码)。
如果我们以字符串形式接收IP地址,则将其与字符串进行比较可能比将其转换为整数表示更为有效。
但是我会确定这两个解决方案是否可以确定,如果此操作需要几毫秒(纳秒!);
我们是否存在效率问题?
如果是这样,那么一定要张贴代码(或者伪代码),我们可以在尸体上取货。
如果没有,那么我建议我们尝试一些简单的事情,例如将条目存储在排序列表中,以及使用环境中现有的Sort()
和Find()
。
意思是说我们应该将其作为文本字符串进行比较还是将int转换为int并作为int进行比较?
这通常不是这类查找的瓶颈。我们可以尝试同时实现这两种方法,然后看看哪种方法运行更快。
IP地址查找的真正问题通常是利用我们正在处理IP地址而不只是随机数的事实来进行有效的查询。要做到这一点,我们可以查找LC特里,也许这篇文章
显然,只有当黑名单中包含成千上万个条目时,我们才应该对此感兴趣。如果只有10到20个条目,则应首选线性搜索,确实更有趣的问题是文本比较与整数比较。
整数比较比字符串比较快得多。
如果将整数存储在排序列表中,则查找整数的速度要比未排序列表中的整数快。
我已经做到了,并且已经测试过,使用无符号int(32位)是最快的,我假设我们正在将其与字符串表示形式进行比较。
可能对我们有所帮助的另一件事是在创建表时,过去我有2个列:LowIP和HighIP。这样,我就可以通过1条记录将IP的整个范围列入黑名单,并且通过检查该范围内的IP仍然可以获得良好的性能。
我曾经继承过代码,有人认为将IP地址存储为4个int是一件很不错的事情,除了他们花了所有时间来转换为int或者从int转换。
将它们作为字符串保存在数据库中要容易得多,并且只需要一个索引即可。我们会惊讶于sql server能够很好地索引字符串而不是4列整数。但是此IP列表不是要列入黑名单。数据库往返非常昂贵。
如果数据库过大,请将它们存储在内存中的字典中,但这只是一个猜测,因为我们不知道我们需要比较多少个。由于大多数哈希码是32位整数,而IPv4地址是32位,因此IP地址本身可能只是一个很好的哈希码。
但是,正如其他人指出的那样,最好的选择可能是减少服务器上的负载并购买专用的硬件。也许我们最近在内存中保留了列入黑名单的IP,并定期将新的IP发布到路由器。
如果我们是试图在路由器内部制作一些软件的人,那么我们将需要研究数据结构书并创建类似b树的东西。
基数或者PATRICIA Trie是为此的最佳结构。
签出C语言源的流工具:
http://www.splintered.net/sw/flow-tools/
我几年前从事过这项工作。
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); }
因为我们得到了地址字节。