Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 实施黑名单的最有效方法_C_Performance_Algorithm - Fatal编程技术网

C 实施黑名单的最有效方法

C 实施黑名单的最有效方法,c,performance,algorithm,C,Performance,Algorithm,我正在开发一个Ip过滤器,我正在猜测如何使用任何类型的数据结构,开发一个非常高效和快速的黑名单过滤器 我想做的很简单,每个传入/传出连接我都必须检查一个阻塞IP的列表 IP是分散的,内存使用应该是线性的(不依赖于阻止列表的数量,因为我想在有限的系统(自制路由器)上使用) 我有时间,可以从零开始创造任何东西。困难对我来说并不重要。 如果您可以使用任何东西,您应该做什么?哈希表就是一种方法。 它们的查找、插入和删除的平均复杂度为O(1)! 它们往往比树占用更多的内存,但速度要快得多 由于您只需使用3

我正在开发一个Ip过滤器,我正在猜测如何使用任何类型的数据结构,开发一个非常高效和快速的黑名单过滤器

我想做的很简单,每个传入/传出连接我都必须检查一个阻塞IP的列表

IP是分散的,内存使用应该是线性的(不依赖于阻止列表的数量,因为我想在有限的系统(自制路由器)上使用)

我有时间,可以从零开始创造任何东西。困难对我来说并不重要。
如果您可以使用任何东西,您应该做什么?

哈希表就是一种方法。 它们的查找、插入和删除的平均复杂度为O(1)! 它们往往比树占用更多的内存,但速度要快得多

由于您只需使用32位整数(当然,您可以将IP转换为32位整数),因此操作将非常简单和快速

您可以只使用排序数组。插入和删除成本为O(n),但查找成本为O(logn),尤其是每个ip的内存仅为4字节。 实现非常简单,可能太多了:D

二叉树的查找、插入和删除的复杂性为O(logn)。 一个简单的二叉树是不够的,但是,您需要一个AVL树或红黑树,这可能是非常烦人和复杂的实现。 AVL和RBT树能够自我平衡,我们需要它,因为不平衡树的查找时间复杂度最差为O(n),这与简单链表的查找时间复杂度相同

如果你需要禁止ip范围而不是单一和唯一的ip,那么你可能需要Patricia Trie,也称为基数树,它们是为单词词典和ip词典而发明的。 但是,如果写得不好\不平衡,这些树可能会变慢。 对于简单的查找,哈希表总是更好!它们太快了,不可能是真的:)

现在,关于同步:

如果在应用程序启动时只填写一次黑名单,则可以使用简单的只读哈希表(或基数树),该哈希表在多线程和锁定方面没有问题

如果您不经常需要更新,我建议您使用读写器锁

如果您需要非常频繁的更新,我建议您使用并发哈希表。 警告:不要自己写,它们非常复杂且容易出错,请在web上找到实现! 他们使用了大量(相对)新处理器的原子CAS操作(CAS意味着比较和交换)。这是一组特殊的指令或指令序列,允许在单个原子操作中比较和交换内存中的32位或64位字段,而无需锁定。 使用它们可能很复杂,因为你必须非常了解你的处理器、操作系统、编译器以及算法本身。 有关CAS的更多信息,请参阅

并发AVL树被发明了,但它太复杂了,我真的不知道该说些什么:)例如

我刚刚发现并发基数树存在: 但它也相当复杂

并发排序数组不存在当然,更新时需要读写器锁

还要考虑处理非并发哈希表所需的内存量可能非常少:对于每个IP,需要4个字节的IP和一个指针。 您还需要一个大的指针数组(或带有一些技巧的32位整数),其大小应该是一个素数,大于应该存储的项数。 当然,如果需要的话,哈希表也可以自行调整大小,但它们也可以存储比素数更多的项,但代价是查找时间变慢

对于树和哈希表,空间复杂度都是线性的

我希望这是一个多线程应用程序,而不是多进程应用程序(fork)。 如果不是多线程,就不能以快速可靠的方式共享一部分内存。

最有效”是一个难以量化的术语。很明显,如果你有无限的内存,你会为每个IP地址都有一个bin,并且可以立即索引到其中

一个常见的折衷方法是使用B-树类型的数据结构。可以为IP地址的前8位预设一级存储箱,该存储箱可以存储指向当前阻止的所有IP地址的指针和列表大小。第二个列表将被填充,以防止不必要的
memmove()
调用和可能的排序。(将列表的大小和长度存储在内存中,可以在插入时间稍贵的情况下对列表进行就地二进制搜索。)

例如:

127.0.0.1 =insert=> { 127 :: 1 }
127.0.1.0 =insert=> { 127 :: 1, 256 }
12.0.2.30 =insert=> { 12 : 542; 127 :: 1, 256 }

这种数据结构的开销最小,并且总存储大小是固定的。显然,更糟糕的情况是大量具有相同最高阶位的IP地址。

提高此类系统性能的一种方法是使用Bloom过滤器。这是一种概率数据结构,占用很少的内存,其中可能出现误报,但不会出现误报

当您想查找IP地址时,首先要签入Bloom筛选器。如果错过了,你可以马上让车辆通行。如果成功,您需要检查您的权威数据结构(例如哈希表或前缀树)

您还可以创建一个“Bloom筛选器中的命中但实际允许”地址的小型缓存,该缓存在Bloom筛选器之后但在权威数据结构之前进行检查


基本上,我们的想法是以牺牲慢路径(IP地址被拒绝)为代价来加速快速路径(允许IP地址)。

如果您变得更加具体,这将非常有帮助,例如,描述一些性能非常重要的场景。如果您的目标是整个IP范围,而不是“分散”的单个IP,则需要完全不同的实现。谢谢jon的提示,我指定了更多!如果