Почему recv не работает, если запрошенный размер буфера превышает объем доступных данных?

В основе транспортного стека TCP лежит ряд ограничений буфера, иногда документируемых их авторами. Думаю, в WinXP SP3 я столкнулся с одним из них и не могу понять, почему.

Я реализовал простой клиент для получения данных с сервера (написан коллегой на Java). Протокол заключается в записи длины данных (в сетевом порядке) в четыре байта, а затем данных. Сервер записывает данные в поток TCP блоками по 1024 байта. Клиент правильно получает длину буфера данных, выделяет память и многократно вызывает recv в цикле, чтобы получить все данные:

unsigned int TCP_BlockSize = 4096;
unsigned int len;
int result;

...code to request len...
unsigned char *buf = new unsigned char[len];

if( len > TCP_BlockSize)
{
Uint32 currentLen = 0;
result = 0;
Uint32 failCount = 0;
while( currentLen < len && result >= 0)
{
        result = recv( sock, buf + currentLen, TCP_BlockSize );
        if( result > 0 )
    {
        currentLen = currentLen + result;
    }
    else
        {
    break;
        }
}
}

Если я установлю TCP_BlockSize равным 4095 или ниже, все будет хорошо, и я смогу получать многомегабайтные передачи. Когда я пытаюсь получить блоки размером 4096, последний запрос оставшихся данных, а именно len — currentLen ‹ TCP_BlockSize, всегда терпит неудачу с возвращаемым значением -1 и errno = 0. Я попробовал несколько экспериментов, таких как обрезка размера данные передаются, и где-то между 815054 и 834246 байт все идет бум для блоков приема 4096 байт.

Еще одна деталь: сервер закрывает сокет после отправки последнего байта. Напрашивается вопрос, почему оставшиеся данные не будут возвращены? Невозврат -1 из recv до тех пор, пока поток не станет и закрытым, выглядит дефектом, так как это двусмысленно, когда поток не пуст и закрыт для приема - 1 из рекв.

Итак, как мне получить последние данные?


person Jason Harrison    schedule 13.01.2009    source источник
comment
Ответ Николаса Манкузо правильный и решает проблему. Спасибо!   -  person Jason Harrison    schedule 14.01.2009


Ответы (1)


Попробуйте что-нибудь вроде...

to_rcv = (len - currentlen < TCP_BlockSize) ? len - currentlen : TCP_BlockSize;
result = recv( sock, buf + currentLen, to_rcv);

Таким образом, окончательный recv будет запрашивать только необходимую сумму, в противном случае он будет запрашивать TCP_BlockSize.

person Nicholas Mancuso    schedule 14.01.2009