Обработка частичного возврата из recv() TCP в C

Я читал Руководство Биджа по сетевому программированию, чтобы разобраться с TCP-соединениями. В одном из примеров клиентский код для простого TCP-клиента выглядит так:

if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
    perror("recv");
    exit(1);
}

buf[numbytes] = '\0';

printf("Client: received '%s'\n", buf);

close(sockfd);

Я установил размер буфера меньше общего количества отправляемых байтов. Я не совсем уверен, как я могу получить другие байты. Должен ли я перебрать recv() пока я не получу '\0'?

* Примечание на стороне сервера, я также реализую его sendall() функция, поэтому он должен на самом деле отправлять все клиенту.

Смотрите также 6.1. Простой Stream Server в руководстве.

3 ответа

Решение

Да, вам понадобится несколько recv() звонки, пока у вас нет всех данных.

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

Лучше, если полученные данные каким-то образом кодируют длину всех данных. Читайте как можно больше данных, пока не узнаете, какова длина, затем читайте, пока не получите length данные. Для этого возможны различные подходы; наиболее распространенным является сделать буфер достаточно большим, чтобы вместить все данные, когда вы знаете, какова длина.

Другой подход заключается в использовании буферов фиксированного размера и всегда пытаться получить min(missing, bufsize), убывающий missing после каждого recv(),

Первое, что вам нужно научиться при программировании TCP/IP: 1 write/send звонок может занять несколько recv звонки, чтобы получить, и несколько звонков записи / отправки может потребоваться только 1 recv позвонить, чтобы получить. И что-нибудь промежуточное.

Вам нужно будет зацикливаться, пока у вас не будут все данные. Возвращаемое значение recv() говорит вам, сколько данных вы получили. Если вы просто хотите получить все данные по TCP-соединению, вы можете выполнить цикл до recv() возвращается 0 - при условии, что другой конец закрывает TCP-соединение после завершения отправки.

Если вы отправляете записи / строки / пакеты / команды или что-то подобное, вам нужно создать свой собственный протокол по TCP, который может быть таким же простым, как "команды с разделителями \n".

Простой способ прочитать / проанализировать такую ​​команду - прочитать 1 байт за раз, создать буфер с полученными байтами и проверить наличие \n байт каждый раз. Чтение 1 байта крайне неэффективно, поэтому вы должны читать большие куски за раз.

Так как TCP ориентирован на поток и не предоставляет границ записи / сообщения, он становится немного сложнее - вам придется recv кусок байтов, проверьте полученный буфер для \n byte, если он есть - добавить байты к ранее полученным байтам и вывести это сообщение. Затем проверьте остаток буфера после \n - которые могут содержать еще одно целое сообщение или только начало другого сообщения.

Да, вы должны перебрать recv() пока не получишь '\0' или произошла ошибка (отрицательное значение от recv) или же 0 от recv(), Для первого варианта: только если этот ноль является частью вашего протокола (сервер отправляет его). Однако из вашего кода кажется, что ноль просто для того, чтобы иметь возможность использовать содержимое буфера в качестве C-строки (на стороне клиента).

Проверка на возвращаемое значение 0 от recv: это означает, что соединение было закрыто (это может быть частью вашего протокола, что это происходит.)

Другие вопросы по тегам