Linux-ioctl с FIONREAD всегда 0

Я пытаюсь узнать, сколько байтов можно прочитать в моем TCP-сокете. Я вызываю ioctl с флагом "FIONREAD", который должен фактически дать мне это значение. Когда я вызываю функцию, я получаю как return val 0 (так что нет ошибки), но и мой целочисленный аргумент получает значение 0. Это не было бы проблемой, но когда я вызываю метод recv (), я фактически читаю некоторые байты из сокета. Что я делаю не так?

// вот код:

char recBuffer[BUFFERLENGTH] = {0};
int bytesAv = 0;
int bytesRead = 0;
int flags = 0;
if ( ioctl (m_Socket,FIONREAD,&bytesAv) < 0 )
{
    // Error
}
if ( bytesAv < 1 )
{
    // No Data Available
}
bytesRead = recv(m_Socket,recBuffer,BUFFERLENGTH,flags);

когда я называю функция recv i acutally считывает некоторые допустимые данные (которые я ожидал )

4 ответов


это происходит очень быстро, поэтому вы ничего не видите. Что вы делаете:

  • ioctl: есть ли данные для меня ? нет, пока ничего
  • recv: пока есть данные для меня. Спустя некоторое (короткое) время: вот ваши данные

так что если вы действительно хотите увидеть FIONREAD, просто подождите.

/* Try FIONREAD until we get *something* or ioctl fails. */
while (!bytesAv && ioctl (m_Socket,FIONREAD,&bytesAv) >= 0)
    sleep(1);

реальный ответ здесь-использовать select (2), Как сказал cnicutar. Тоби, ты не понимаешь, что у тебя расовое заболевание. Сначала вы смотрите на сокет и спрашиваете, сколько там байтов. Затем, пока ваш код обрабатывает блок "нет данных здесь", байты принимаются аппаратным & OS асинхронно к вашему приложению. Таким образом, к моменту вызова функции recv() ответ "нет доступных байтов" больше не является истинным...

if ( ioctl (m_Socket,FIONREAD,&bytesAv) < 0 )
{ // Error 
}

// BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!

if ( bytesAv < 1 ) // AND HERE!
{
    // No Data Available
    // BUT BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!
}

// AND MORE BYTES MIGHT BE RECEIVED BY HARDWARE/OS HERE!

bytesRead = recv(m_Socket,recBuffer,BUFFERLENGTH,flags);
// AND NOW bytesRead IS NOT EQUAL TO 0!

конечно, a небольшой сон, вероятно, исправил вашу программу два года назад, но он также научил вас ужасной практике кодирования, и вы потеряли возможность научиться правильно использовать сокеты с помощью select().

далее, как сказал Кароли хорват, вы можете сказать recv не читать больше байтов, чем вы можете хранить в буфере, который передал пользователь. Затем ваш интерфейс функции становится "этот fn вернет столько байтов, сколько доступно в сокете, но не больше, чем [размер буфера, который вы передали в."]

это означает, что этой функции больше не нужно беспокоиться об очистке буфера. Вызывающий может вызвать вашу функцию столько раз, сколько необходимо, чтобы очистить все байты из нее (или вы можете предоставить отдельный fn, который отбрасывает данные оптом и не связывает эту функциональность в какой-либо конкретной функции сбора данных). Ваша функция является более гибкой, не делая слишком много вещей. Затем вы можете создать функцию-оболочку, которая соответствует вашим потребностям в передаче данных конкретного приложения, и что ФН вызывает get_data ФН и ФН clear_socket как необходимые для конкретного приложения. Теперь вы создаете библиотеку, которую можете переносить из проекта в проект, и, возможно, работу за работой, Если Вам повезет и у вас будет работодатель, который позволит вам взять с собой код.


использовать выбрать() тогда функции ioctl(то fionread), то вызовов recv()


вы не делаете ничего плохого, если вы используете блокировку ввода-вывода recv() будет блокировать до тех пор, пока данные не будут доступны.