Таким образом, вам нужна возможность вставлять элементы, находить, обновлять и удалять их по идентификатору. Вам также необходимо удалить клиентов, к которым не обращались в течение некоторого периода времени. Допустим, время определяется константой: OldClientRemovalInterval
.
Структура данных клиента будет содержать идентификатор, IP, порт и время последнего доступа.
Вот один из способов сделать это:
Ведение ассоциативного массива клиентских записей, ключом которого является идентификатор. Стандартная библиотека шаблонов C ++ имеет несколько различных структур данных ассоциативных массивов (map
, hash_map
и т. Д.). A hash_map
дает очень быстрое время доступа. Вы можете вставлять, обновлять или удалять элементы очень быстро.
Для удаления ведите очередь FIFO, которая содержит идентификаторы клиентов и ожидаемое время удаления. Всякий раз, когда клиентская запись вставляется или обновляется, создайте вторую структуру { ClientID, RemovalTime }
, с вычислением RemovalTime
путем добавления OldClientRemovalInterval
к текущему времени.
Элементы в очереди упорядочены по увеличению времени удаления. Периодически проверяйте очередь, удаляя любые элементы, время удаления которых истекло.
Обратите внимание, однако, что клиент мог быть обновлен, так как он был добавлен в очередь. Поэтому, когда вы берете что-то из очереди, вы должны найти этого клиента в ассоциативном массиве и определить, действительно ли это нужно удалить. Что-то вроде:
ClientID = RemoveItemFromQueue();
Client = GetClientRecord(ClientID);
ClientRemovalTime = Client.LastAccess + ClientRemovalInterval;
if (ClientRemovalTime <= CurrentTime)
RemoveClient(ClientId);
Это фактически потребует, чтобы структура данных поддерживала 30K транзакций в секунду (для каждой вставки / обновления будет соответствующий поиск и возможное удаление). Но hash_map
должен справиться с этим без проблем.
Как вы проверяете очередь, зависит от вас. Вы можете сделать это по таймеру или во втором потоке, но тогда у вас возникнут проблемы с блокировкой доступа к очереди и ассоциативному массиву. Возможно, лучшая идея - запускать алгоритм удаления после каждой вставки / обновления, удаляя любой элемент, время которого истекло. Или, чтобы не тратить слишком много времени на удаление, попросите удалить до двух старых клиентов для каждой вставки / обновления. То есть:
InsertOrUpdateClient();
// now remove up to 2 items
for (int i = 0; i < 2; ++i)
{
if (queue.Peek().RemovalTime >= CurrentTime)
{
// Remove item from queue,
// and potentially remove client from associative array.
}
else
{
break;
}
}
Это позволит не тратить слишком много времени на удаление, но в среднем не позволит старым клиентам засорять структуру данных. Единственный недостаток заключается в том, что удаление не происходит, если нет вставок / обновлений. Таким образом, после длительного периода бездействия стол может быть полон старых клиентов. Если это важно, у вас может быть таймер, который периодически отправляет нулевой запрос (например, со специальным идентификатором клиента, равным -1), который не обновляет ассоциативный массив, но выполняет удаление.