Одна проблема с функцией чтения в C ++ - PullRequest
0 голосов
/ 26 февраля 2011

Я использую функцию чтения для чтения данных из сокета, но когда данные больше 4k, функция чтения просто читает часть данных, например, меньше 4k. Вот код ключа:

mSockFD = socket(AF_INET, SOCK_STREAM, 0);
if (connect(mSockFD, (const sockaddr*)(&mSockAdd), sizeof(mSockAdd)) < 0)
{
    cerr << "Error connecting in Crawl" << endl;
    perror("");
    return false;
}
n = write(mSockFD, httpReq.c_str(), httpReq.length());
bzero(mBuffer, BUFSIZE);
n = read(mSockFD, mBuffer, BUFSIZE);

Обратите внимание, что BUFSIZE намного больше, чем 4k. Когда объем данных составляет всего несколько сотен байтов, функция чтения работает как положено.

1 Ответ

6 голосов
/ 26 февраля 2011

Это задуманно и следовало ожидать.

Короткий ответ на ваш вопрос: вы должны продолжать звонить «читать», пока не получите все ожидаемые данные.То есть:

   int total_bytes = 0;
   int expected = BUFSIZE;
   int bytes_read;
   char *buffer = malloc(BUFSIZE+1); // +1 for null at the end
   while (total_bytes < expected)
   {
       int bytes_read = read(mSockFD, buffer+total_bytes, BUFSIZE-total_bytes);
       if (bytes_read <= 0)
           break;
       total_bytes += bytes_read;
   }
   buffer[total_bytes] = 0; // null terminate - good for debugging as a string

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

Когда другая сторона отправляет N байтов, вы можетеповезет и получит все сразу.Но вы должны запланировать получение N байтов, распределенных между несколькими вызовами recv.За исключением реальной сетевой ошибки, вы в конечном итоге получите все N байтов.Сегментация, фрагментация, размер окна TCP, MTU и схема разбиения данных на уровне сокетов являются причинами всего этого.При получении частичных данных уровень TCP не знает, сколько еще предстоит сделать.Он просто передает то, что имеет, в приложение.Приложение решает, достаточно ли оно получено.

Аналогично, вызовы "send" могут объединяться в один пакет вместе.

Могут быть ioctl и такие, которые сделают сокетблокировать, пока все ожидаемые данные не будут получены.Но я не знаю ничего лишнего.

Кроме того, не используйте чтение и запись для сокетов.Используйте recv и отправьте.

Прочитайте эту книгу .Это изменит вашу жизнь в отношении сокетов и TCP:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...