Лично я думаю, что вам лучше прочитать четыре байта IP как длинную без знака, которая даст вам число примерно в диапазоне 0 - 2 ^ 32-1. Затем вы выясняете, сколько потоков вы хотите иметь активными одновременно, и это будет размер таблицы индекса.
Возьмите 2000, например. Это означает, что вы хотите отобразить 2 ^ 32 числа примерно на 2 ^ 11 индейцев (для передачи информации). Это не сработает, потому что хеширование почти никогда не работает, если заполнено до 100%, и даже 90% может быть трудным. Использование индексной таблицы, которую вы заполняете только до 50% (4000 унций) или даже до 25% (8000), не имеет большого значения для сегодняшней памяти.
Точный размер индексной таблицы должен быть неравномерным числом местоположений и предпочтительно простым числом. Это потому, что вам, скорее всего, понадобится некоторая обработка переполнения для обработки коллизий (два или более числа ip, которые после хэширования указывают на одно и то же место в индексной таблице) - что вы получите. Обработка переполнения должна быть на другое простое число меньше размера таблицы индекса. Все эти простые числа! Что с ними в любом случае?
Я проиллюстрирую на примере (на С):
idxsiz = prime(2000 * 2); // 50% loading
ovfjmp = prime(idxsiz/3);
...
изначально заполнить таблицу позиций idxjmp пометкой UNUSED (-1). Подготовьте маркировку DELETED (-2).
Ваш IP-номер входит в систему, и вы ищете его запись потока (может существовать или не существовать):
stoppos = ip % idxsiz; /* modulo (division) just this once */
i = stoppos;
do
{
if (index[i] == UNUSED) return NULL;
if (index[i] != DELETED)
{
flowrecptr = &flow_record[index[i]];
if (!flowrecptr->in_use) {/* hash table is broken */}
if (flowrecptr->ip == ip) return flowrecptr;
}
i += ovfjmp;
if (i >= idxsiz) i -= idxsiz;
}
while (i != stoppos);
return NULL;
UNUSED служит маркером того, что этот индекс никогда не использовался и что поиск должен быть остановлен. DELETED служит маркером того, что этот индекс использовался, но больше не используется. Это означает, что поиск должен продолжаться.
Это было, когда вы пытались получить. Вы получили NULL от get, поэтому вам нужно выполнить пут, который вы начинаете, находя первую позицию индекса, содержащую UNUSED или DELETED. Замените это значение индексом первой / следующей свободной строки в таблице flow_record. Пометить строку как in_use. Поместите исходный номер ip в член ip строки flow_record.
Это очень простой, но очень эффективный способ создания механизма хеширования. Практически каждая оптимизация в виде специальных функций, которые будут использоваться после сбоя той или иной функции, будет повышать эффективность хеширования.
Использование простых чисел гарантирует, что - в худшем случае, когда все местоположения индекса заняты - механизм будет проверять каждое местоположение. Чтобы проиллюстрировать это: предположим, что idxsiz равномерно делится на ovfjmp: вам не придется много говорить о переполнении. 35 и 7 приведет к тому, что местоположения 0,7,14,21 и 28 будут проверены, прежде чем индекс перейдет к 0, где во время проверки остановится поиск.
---------------------- OOPS!
Я пропустил, что вы также хотели номер порта. Предполагая ip V4, это означает 6 байтов адреса. Прочитайте это как 64-разрядное целое число без знака и очистите верхние 16 бит / 2 байта. Затем вы делаете расчет по модулю.