Как отбросить входящие пакеты в сырой сокет?

Я пишу приложение 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;
}
Другие вопросы по тегам