В основе транспортного стека 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 из рекв.
Итак, как мне получить последние данные?