#c #tcp
#c #tcp
Вопрос:
Я тестирую свой эхо-сервер TCP с помощью Telnet, я вижу, что клиент подключается к серверу и отправляет символ, а взамен сервер возвращает клиенту строку.
Теперь моя проблема в том, что с помощью этого recv () в бесконечном цикле я могу получить только один символ (даже если клиент обычно отправляет строку).
Вот как я делаю, чтобы получить дейтаграмму от клиента
TCP-СЕРВЕР
while(1)
{
socket = accept(server_socket, (struct sockaddr *)amp;client_address, (socklen_t)amp;client_length);
recv(socket, recv_buffer, sizeof(recv_buffer), 0);
printf("Received string from client is %s", recv_buffer);
/*then I send my string to the client*/
send(socket, send_buffer, sizeof(send_buffer), 0);
}
Моя проблема в том, что моя процедура recv () считывает только один символ, даже если клиент хочет отправить целую строку. Есть ли способ, как я могу заставить эту процедуру recv () подождать, пока она получит все символы от клиента, а затем отправить ответ клиенту.
Любые предложения будут оценены
С уважением
Комментарии:
1. В качестве побочной проблемы … стоит отметить, что Telnet является клиентом терминала, поэтому он собирается передавать на ваш сервер нечто большее, чем просто строку, которую вы вводите в него, поэтому не удивляйтесь, если вы получите некоторые управляющие коды, которые на первый взгляд могут показаться мусором…
2. моя проблема в том, что я получаю только один символ, хотя клиент отправляет мне полную строку, которую я набираю на клиенте telnet вручную. Как только я набираю письмо, оно принимается сервером ma, и мой сервер отправляет текст, который можно увидеть на выводе терминала telnet.
Ответ №1:
Ну, вы делаете что-то неправильно. Посмотрите на определение recv
:
int recv(int s, void *buf, size_t len, int flags);
Таким образом, он получает len
количество байтов. Вы передали sizeof(recv_buffer)
в качестве параметра len. Теперь я предполагаю, что recv_buffer
определяется как char*
. Получение sizeof
указателя означает, что вы получаете количество байтов, необходимое для хранения этого указателя, вместо памяти, на которую он указывает.
Вместо этого сделайте что-то подобное:
const int buf_len = 100;
char recv_buffer[buf_len];
recv(socket, recv_buffer, buf_len, 0);
printf("Received string from client is %s", recv_buffer);
Комментарии:
1. Вообще не будет работать — нет гарантии, что строка может быть получена с помощью одного вызова recv().
2. @unapersson: Верно, но усложняет историю. Проблема заключалась в получении
sizeof
указателя.3. Я устал от предложенного вами способа, но результат все тот же
Ответ №2:
Вам нужно создать строку, которую вы получаете самостоятельно, в цикле, используя возвращаемое значение recv()
, чтобы определить, сколько байт вы на самом деле получили. TCP / IP не гарантирует, что все данные, отправленные при одном вызове на send()
, могут быть получены при одном вызове на recv()
. И вы должны проверять возвращаемое значение каждой вызываемой вами функции сокетов, чтобы проверить фактическую отправленную / полученную длину и наличие ошибок.
Комментарии:
1. Я проверил возвращаемое значение recv (), и оно показывает мне ‘1’, это означает, что как только я получаю символ, моя функция send () вызывает и отправляет строку.
2. @Devb Вы должны продолжать вызывать recv, пока не получите все ожидаемые символы.
Ответ №3:
Ваш код — это катастрофа (извините за прямоту, но лучше всего говорить прямо).
recv() возвращает количество фактически прочитанных байтов. Не только это, но и то, что это не очистит предыдущее содержимое буфера, и оно будет заполнено до конца буфера, если есть доступные данные. Все это означает, что вы не можете обрабатывать содержимое буфера как строку, завершающуюся нулем.
Вам нужно сделать что-то вроде:
ssize_t bytesRead = 1;
char recv_buffer[SOME_SIZE];
while (bytesRead > 0)
{
int bytesRead = recv(socket, recv_buffer, SOME_SIZE, 0);
if (bytesRead > 0)
{
// do something with the bytes. Note you cannot guarantee that the buffer contains a valid C string.
}
}
if (bytesRead == -1)
{
// report error from errno
}
else
{
// bytesRead == 0 have reached end of file (i.e. socket closed at other end)
}
Нет способа заставить recv дождаться заполнения буфера перед возвратом. Он будет ждать, пока не освободится несколько байтов, а затем вернется. Кстати, то же самое относится и к отправке. Вы не можете предположить с помощью одного вызова для отправки, что все ваши байты действительно были отправлены. Вам также нужно поместить отправку в цикл:
ssize_t totalBytesWritten = 0;
ssize_t bytesWritten = 0;
while (bytesWritten >= 0 amp;amp; totalBytesWritten < bytesToWrite)
{
bytesWritten = send(socket, sendBuffer totalBytesWritten, bytesToWrite - totalBytesWritten, 0);
if (bytesWritten > 0)
{
totalBytesWritten = bytesWritten;
}
}
if (bytesWritten == -1)
{
// error
}
Комментарии:
1. Я должен сказать, что после того, как я последовал вашему совету, я все еще не могу получить желаемый результат, для отправки он отлично работает с моим старым кодом. Я все еще понятия не имею