您可以将子网表示为 int 值,将它们全部放在一个数组中,对其进行排序,然后对其使用二进制搜索。
尽管从那时起 long 可能会更好,但您不必在二进制搜索中处理负数。
最多需要 10 个步骤才能找到子网。尝试可能需要例如/25 子网的 25 个步骤。
还要记住,1000 长只有 8 kb。这将很容易适应 CPU 缓存,使其非常快。
当然,您可以使用第二个数组来存储每个掩码所属的子网。
这是 Scala 中的示例
findMaskIdx 使用二分搜索查找给定掩码的索引(子网定义的 ip 部分)。
如果它找不到任何东西,它会返回大于它搜索的第一个掩码的索引。
findIpIdx 接受一个 IP 地址并返回它所属的子网定义的索引,如果没有找到则返回 -1。
findIpIdx 每秒可以运行大约 100 到 2 亿次。
所以它似乎相当快。
这种方法只有一个问题。如果两个不同大小的子网重叠,则代码可能会找到错误的子网。
但我希望这应该不会太难解决。
def ipStringToInt(s: String): Int = {
var ip = 0
for(num <- s.split("\\.")) {
ip = ip * 256 + num.toInt
}
ip
}
def parseSubnet(s: String): (Long, Int) = {
val mask_length = s.split("/")
val length = if(mask_length.size > 1) mask_length(1).toInt else 32
var mask = ipStringToInt(mask_length(0)) & 0xFFFFFFFFL
(mask, length)
}
val subnetGroups = Vector(
Vector("61.232.85.0/25", "61.232.86.0/27"),
Vector("123.234.12.24/16", "1.2.3.4"),
Vector("61.232.87.5", "253.2.0.0/16")
)
val subnetData = (for {
(group, idx) <- subnetGroups.zipWithIndex
maskString <- group
(mask, length) = parseSubnet(maskString)
} yield (mask, length, idx)).sortBy(_._1)
val masks: Array[Long] = subnetData.map(_._1).toArray
val maskLengths: Array[Int] = subnetData.map(_._2).toArray
val groupNr: Array[Int] = subnetData.map(_._3).toArray
def findMaskIdx(ip: Long): Int = {
var low = 0
var high = masks.size
while(high > low) {
val mid = (low + high)/2
if(masks(mid) > ip) high = mid
else if(masks(mid) < ip) low = mid + 1
else return mid
}
low
}
def findIpIdx(ip: Int): Int = {
val ipLong = ip & 0xFFFFFFFFL
var idx = findMaskIdx(ipLong)
if(idx < masks.size && masks(idx) == ipLong) return idx
idx -= 1
if(idx < 0) return -1
val m = (0xFFFFFFFF00000000L >>> maskLengths(idx)) & 0xFFFFFFFFL
if((m & masks(idx)) == (m & ipLong)) return idx
return -1
}
println("subnet data (mask, bit length of mask, index of subnet group):")
println(subnetData.map {
case (mask, length, idx) => (mask.toHexString, length, idx)
})
println()
println("masks = " + masks.toVector.map(_.toHexString))
println()
def testIP(ipString: String) {
println("ipString = " + ipString)
val ip = ipStringToInt(ipString)
val dataIdx = findIpIdx(ip)
println("dataIdx = " + dataIdx)
if(dataIdx >= 0) {
val data = subnetData(dataIdx)
println("data = " + (subnetData(dataIdx) match {
case (mask, length, idx) => (mask.toHexString, length, idx)
}))
}
println()
}
testIP("61.232.86.12")
testIP("253.2.100.253")
testIP("253.3.0.0")