Как отбросить входящие пакеты в сырой сокет?
Я пишу приложение C/C++ под Linux, которое читает данные из необработанного сокета (для пакетов ICMP). Вопрос: есть ли способ отбросить все данные, которые все еще находятся в очереди в сокете?
Проблема в том, что после некоторого времени сна в очереди находятся данные, которые меня не интересуют; поэтому было бы лучше просто сказать сокету "забыть все данные, которые вы сейчас буферизировали", так что если я попаду в цикл select()/recvfrom(), то получу только те данные, которые были получены недавно.
Есть ли лучший способ, чем сначала зайти в отдельный цикл poll()/recvfrom()? Может быть, какой-нибудь вызов API сокета? Даже портативный?:-)
7 ответов
Вы не можете просто сделать recvfrom()
во временный буфер и сбросить буфер?
Во время простоя вы можете отключить сокет, установив нулевой размер буфера приема:
int optval = 0; /* May need to be 1 on some platforms */
setsockopt(sockDesc, SOL_SOCKET, SO_RCVBUF, (char *)(&optval), sizeof(optval));
Повторно включите, установив "optval" в больший буфер (например, 4096).
Я бы порекомендовал не спать вообще. Используется вызов select для обработки данных сразу после их поступления.
while (1)
{
FD_ZERO (&sockets);
FD_SET (raw_socket, &sockets);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (select (raw_socket + 1, &sockets, NULL, NULL, &timeout))
{
if (FD_ISSET (raw_socket, &sockets))
{
// handle the packet
}
}
else
{
/* Select Timed Out */
fprintf(stderr, "Timed out");
}
}
Кроме того, при создании вашего необработанного сокета вы можете указать, что вас интересуют только пакеты icmp.
Единственный способ, которым я знаю, как сделать это надежно, это закрыть сокет.
Стандартной процедурой в приложениях промежуточного программного обеспечения является выделение потока для обслуживания запросов ввода-вывода с приоритетом, установленным выше, чем у других потоков приложения. Когда поток ввода-вывода получает пакет, он помещает его в очередь на прикладном уровне. Когда у приложения есть свободное время, оно удаляет следующий пакет.
Эта архитектура лежит в основе TIBCO Rendezvous, которая используется во многих рыночных данных и системах обмена корпоративными сообщениями в режиме реального времени. Предостережение в том, что вы обычно хотите ограничить размер очереди, чтобы приложение не получало информацию от менеджера OOM. Протокол между потоком ввода-вывода и прикладным уровнем может варьироваться от простой асинхронной очереди до более сложной предметной фильтрации, списков приоритетов и поддержки потоковых пулов для параллельного декодирования входящих данных.
Я не пробовал, и это может быть совершенно неразумно по соображениям производительности (но если ваше приложение все равно спит, это может не быть проблемой), но: вы можете попробовать установить буфер приема сокета на очень маленькое значение перед сном. Я надеюсь, что это приведет к тому, что сокет не сможет буферизовать данные, поступающие, когда приложение не прослушивает. Это своего рода длинный выстрел.
В качестве альтернативы, возможно, сброс размера приемного буфера после сна, когда вы будете готовы начать чтение снова, также приводит к его сбросу. Конечно, эти уловки - это просто так, и даже если они работают, они наверняка не переносимы. Я просто подумал, что поделюсь этой идеей, если у вас есть шанс проверить это, это может вам помочь.
Можете ли вы сделать что-то подобное прямо перед сном?
for(n=0;n<=MAX_BUFFER_SIZE;n++)
{
recv_buffer[n] = 0;
}