最佳IP子网匹配
以下代码似乎是我的程序中最热门的地方。
JAVA_OPTS=-Xprof 输出:
Compiled + native Method
5.7% 173 + 0 scala.collection.IndexedSeqOptimized$class.slice
5.1% 156 + 0 scala.collection.IndexedSeqOptimized$class.foreach
2.9% 87 + 0 java.util.regex.Pattern$BmpCharProperty.match
2.5% 76 + 0 scala.collection.IndexedSeqOptimized$class.sameElements
2.4% 73 + 0 trafacct.SubNet.contains
Slice、sameElements 甚至 foreach 调用似乎也是这里最常用的。有人可以就如何优化 contains()
方法提供一两个建议吗?也许有些技术允许字节分析而不将它们转换为整数?或者没有切片的可靠全序列方法?
函数 SubNet.contains() 将 IP 地址与子网进行匹配。
object SubNet {
def toInts(bytes: Seq[Byte]): Seq[Int] = bytes.map(_.toInt & 0xFF)
}
case class SubNet(ip:InetAddress, maskLength:Int) extends HostCategory {
import SubNet.toInts
private val bytes: Int = maskLength / 8
private val subnet = toInts(ip.getAddress)
private val bits = bytes * 8 - maskLength
def contains(host: Host) = {
if (host.ip == null && ip == null) {
true
} else if (this.ip == null) {
false
} else {
val address = toInts(host.ip.getAddress)
if (address.length != subnet.length) {
false
} else {
if (address.slice(0, bytes) != subnet.slice(0, bytes)) {
false
} else {
((address(bytes) >> (8-bits) ^ subnet(bytes) >> (8-bits)) & 0xFF) == 0
}
}
}
}
}
我知道,这种优化不会给我带来更好的吞吐量,我只是觉得我在这个简单的函数中花费这么多时间做错了一些事情。
该代码应该与 IPv6(16 字节)兼容,并且我不喜欢单独处理 IPv4 情况的想法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你本身并没有做错什么;您只是使用旨在易于使用的集合,而不是处理基元时的性能。
如果您想加快速度,可以通过改用数组和 while 循环来获得最大的提升。我并不完全清楚您编写的代码是否适用于 IPv6(除了以 IPv6 格式存储的 IPv4 地址),因为您的子网可能包含超过 256 个项目。另外,通过测试长度,您假设同一地址没有混合的 IPv6/IPv4 表示形式。
我会忘记整个“toInts”的事情,只存储字节数组;然后执行类似的操作(警告,未经测试)
它实际上并不比您原来的解决方案更复杂,并且运行速度应该快 10 倍。
You're not doing anything wrong per se; you're just using collections that are meant for ease of use not performance when handling primitives.
If you want to speed this up, you'll get the largest boost by switching to using arrays and while loops. It's not entirely clear to me that the code you wrote even works for IPv6 except for IPv4 addresses stored in IPv6 format, since you could have a subnet with more than 256 items. Also, by testing lengths you're assuming no mixed IPv6/IPv4 representations of the same address.
I'd forget the whole "toInts" thing and just store byte arrays; then do something like (warning, untested)
It's really not any more complicated than your original solution, and should run ~10x faster.
使用此代码,它无法正确验证。
例如:
但是如果您计算该网络:(1.2.176.0/20)
我用 Scala 重写了这两个网络(IPv4 和 IPv6),并将其发布在 GitHub 上供大家使用。现在它也在范围内进行验证(因此 /20 等将被视为,而旧的没有这样做。)
您可以在 https://github.com/wasted/scala-util/blob/master/src/main/scala/io/wasted/util/InetPrefix.scala
我还创建了一个 关于此的博文。
With this code, it does not validate correctly.
For example:
But if you calculate that network: (1.2.176.0/20)
I rewrote both (IPv4 and IPv6) in Scala put it for everyone on GitHub. It now also validates within ranges (so /20 etc will be regarded, which the old one did not do.)
You can find the code (i separated it into IPv4 and IPv6) at https://github.com/wasted/scala-util/blob/master/src/main/scala/io/wasted/util/InetPrefix.scala
I also created a blogpost about this.