Вопрос

Для моего серверного приложения мне нужно проверить, находится ли IP-адрес в нашем черном списке.

Какой наиболее эффективный способ сравнения IP-адресов?Будет ли преобразование IP-адреса в целое число и их сравнение эффективным?

Это было полезно?

Решение

Зависит от того, какой язык вы используете, но IP-адрес обычно хранится как 32-битное целое число без знака, по крайней мере, на сетевом уровне, что делает сравнения довольно быстрыми.Даже если это не так, если только вы не разрабатываете высокопроизводительное приложение с коммутацией пакетов, это вряд ли станет узким местом в производительности.Избегайте преждевременной оптимизации — создавайте свою программу так, чтобы ее можно было тестировать и масштабировать, а если у вас есть проблемы с производительностью, вы можете использовать профилировщик, чтобы увидеть, где находятся узкие места.

Редактировать:чтобы уточнить, адреса IPv4 хранятся как 32-битные целые числа плюс сетевая маска (которая не требуется для сравнения IP-адресов).Если вы используете более новый и в настоящее время более редкий IPv6, длина адреса будет 128 бит.

Другие советы

32-битные целые числа — это то, что вам нужно, пока вы не начнете иметь дело со 128-битными адресами IPv6.

Вы имеете в виду, следует ли вам сравнить его как текстовую строку или преобразовать int в int и сравнить как int?

Обычно это не является узким местом в такого рода поиске.вы можете просто попробовать реализовать оба метода и посмотреть, какой из них работает быстрее.

Настоящая проблема при поиске IP-адресов обычно заключается в создании эффективных запросов с использованием того факта, что вы имеете дело с IP-адресами, а не просто со случайными числами.для этого вы можете поискать LC трие и возможно Эта статья

Очевидно, это должно вас заинтересовать, только если ваш черный список содержит десятки тысяч или миллионы записей.Если в нем всего 10-20 записей, следует отдать предпочтение линейному поиску, и действительно, более интересным вопросом является сравнение текста и целочисленного сравнения.

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);
  }

потому что вы получили байты адреса.

Да, я обнаружил, что для эффективности это займет много времени, и, конечно, вам придется индексировать IP-адреса, занесенные в черный список, в целочисленной форме.

Используйте такой инструмент, как PeerGuardian, который запрещает входящие TCP/IP-соединения на уровне драйвера к IP-адресам из черного списка.Высокая безопасность, код не требуется (возможно:очень безопасный, потому что код не требуется).

Я сделал это и протестировал, используя беззнаковое целое число (32 бита) является самым быстрым - я предполагаю, что вы сравниваете это со строковым представлением.

Еще одна вещь, которая может вам помочь: при создании таблицы раньше у меня было 2 столбца:LowIP и HighIP;Таким образом, я смог занести в черный список целые диапазоны IP-адресов с одной записью и при этом получить хорошую производительность, проверяя IP-адреса в диапазоне.

Однажды я унаследовал код, в котором кто-то мысль что хранить IP-адреса в виде 4 целых чисел было действительно хорошо, за исключением того, что они тратили все свое время на преобразование в/из целых чисел.

Хранить их в виде строк в базе данных было гораздо проще, и для этого требовался всего один индекс.Вы будете удивлены, насколько хорошо SQL-сервер может индексировать строки, а не 4 столбца целых чисел.Но этот список IP не предназначен для внесения в черный список.Обращение к базе данных туда и обратно обходится довольно дорого.

Если база данных перегружена, сохраните их в словаре в памяти, но это всего лишь предположение, поскольку мы понятия не имеем, сколько вам нужно сравнить.Поскольку большинство хеш-кодов представляют собой 32-битные целые числа, а адреса IPv4 — 32-битные, сам IP-адрес может быть просто хорошим хэш-кодом.

Но, как отмечают другие, лучшим вариантом может быть снижение нагрузки на ваш сервер и покупка специализированного оборудования.Возможно, вы храните в памяти недавно занесенные в черный список IP-адреса и периодически публикуете новые на маршрутизаторе.

Если вы пытаетесь создать какое-то программное обеспечение внутри маршрутизатора, вам нужно будет выудить книгу о структурах данных и создать что-то вроде b-дерева.

Оптимальной структурой для этого является дерево Radix или PATRICIA.

Ознакомьтесь с исходным кодом C для инструментов потока:http://www.splintered.net/sw/flow-tools/

Я работал над этим много лет назад.

Есть ли у вас проблемы с эффективностью?

Если да, то обязательно опубликуйте код (или псевдокод), и мы сможем ковыряться в трупе.

Если нет, то я бы предложил попробовать что-то простое, например сохранить записи в отсортированном списке и использовать существующую среду вашей среды. Sort() и Find().

Сравнение целых чисел выполняется намного быстрее, чем сравнение строк.

Если вы сохраните целые числа в отсортированном списке, вы сможете найти их быстрее, чем в несортированном списке.

если вы получаете IP-адрес в виде строки, сравнение его со строкой может быть более эффективным, чем преобразование его в целочисленное представление.

но я бы профилировал оба решения, чтобы быть уверенным, если несколько миллисекунд (наносекунд!) будут иметь значение для этой операции ;-)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top