Обработка частичного возврата из recv() TCP в C
Я прочитал Beej Guide to Network Programming, чтобы получить доступ к 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. Простой сервер потоков в руководстве.
Ответы
Ответ 1
Да, вам понадобится несколько вызовов recv()
, пока у вас не будет всех данных.
Чтобы узнать, когда это происходит, использование статуса возврата из recv()
не подходит - оно только сообщает вам, сколько байтов вы получили, а не сколько байтов доступно, поскольку некоторые из них все еще могут быть в пути.
Лучше, если полученные вами данные каким-то образом кодируют длину общих данных. Прочитайте столько данных, пока не узнаете, что такое длина, затем прочитайте, пока не получите данные length
. Для этого возможны различные подходы; общий - сделать буфер достаточно большим, чтобы хранить все данные, как только вы знаете, что такое длина.
Другой подход заключается в использовании буферов фиксированного размера и всегда пытайтесь получить min(missing, bufsize)
, уменьшая missing
после каждого recv()
.
Ответ 2
Первое, что вам нужно узнать при программировании TCP/IP: 1 write
/send
вызов может занять
несколько вызовов recv
для приема, а для нескольких вызовов для записи и отправки может потребоваться только один вызов recv
для приема. И что-нибудь между ними.
Вам понадобится цикл, пока у вас не будет всех данных. Возвращаемое значение recv()
сообщает, сколько данных вы получили. Если вы просто хотите получать все данные в TCP-соединении, вы можете зацикливаться до тех пор, пока recv()
не вернет 0
- при условии, что другой конец закрывает TCP-соединение, когда он будет отправлен.
Если вы отправляете записи/строки/пакеты/команды или что-то подобное, вам нужно сделать свой собственный протокол через TCP, что может быть так же просто, как "команды разделены на \n
".
Простым способом чтения/разбора такой команды будет чтение 1 байт за раз, создание буфера с полученными байтами и проверка байта \n
каждый раз. Чтение 1 байт крайне неэффективно, поэтому вы должны читать более крупные фрагменты за раз.
Поскольку TCP ориентирован на поток и не обеспечивает границы записи/сообщения, он становится немного более сложным - вы бы
должны recv
кусок байта, проверить полученный буфер для байта \n
, если он там - добавить байты к ранее принятым байтам и вывести это сообщение. Затем проверьте оставшуюся часть буфера после \n
, которая может содержать другое целое сообщение или только начало другого сообщения.
Ответ 3
Да, вам нужно пройти через recv()
, пока не получите '\0'
или
ошибка (отрицательное значение от recv
) или 0
от recv()
.
Для первого варианта: только если этот ноль является частью вашего
протокол (сервер отправляет его). Однако из вашего кода кажется, что
нуль должен просто использовать буферный контент как
C-строка (на стороне клиента).
Проверка возвращаемого значения 0
из recv
:
это означает, что соединение было закрыто (это может быть часть
вашего протокола, что это происходит.)