Обработка частичного возврата из 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
: это означает, что соединение было закрыто (это может быть частью вашего протокола, что это происходит.)