Я новичок в C++ и программировании сокетов. Я учился в руководстве Beej, поэтому мои коды почти такие же, как и руководство, но я борюсь с действительно странными ошибками.
Во-первых, мой сервер recv() возвращает 0. Согласно документу, клиент должен изящно закрыть соединение для recv(), чтобы вернуть 0. На самом деле это не так. Он возвращает 0, в то же время я все еще получаю данные от клиента. Итак, способ, которым Бэй делает, чтобы получить, не работает для меня. Может ли кто-нибудь объяснить, как это возможно?
char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
buf[numbytes] = '\0';
последняя строка здесь, так как numbytes равно 0, оно отображает все полученные мной сообщения. Поэтому я должен был прокомментировать это. Теперь мой код выглядит так
char buf[MAXDATASIZE];
numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
//buf[numbytes] = '\0';
printf("received: %s\n", buf);
Теперь он работает с получением сообщений, отправленных клиентом. Тем не менее, я сделал некоторые манипуляции с строкой (добавление) на стороне клиента, а затем отправил сообщение. Теперь я посылаю строку длиной 29 на стороне клиента, но сервер получает 41 байт со странными символами. Что я отправил: получено: Войти # 1 Mary 123456 451912345 получено: Войти # 1 Mary 123456 451912345ÿ> É "ÿy @ÿ> Ád
while(1) { // main accept() loop
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
char buf[MAXDATASIZE];
int numbytes;
if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1)
perror("recv");
//buf[numbytes] = '\0'; // this had to be commented out
printf("received: %s\n", buf); // prints out with weird characters
string msgRcved = buf;
close(new_fd);
}
// string loginCredential is loaded with "1 Mary 123456 451912345" at this point
loginCredentials.insert(0, "Login#");
const char* msgToSend = loginCredentials.c_str();
int numbytesSent;
if (numbytesSent = send(sockfd, msgToSend, strlen(msgToSend), 0) == -1)
perror("send");
Я хотел бы знать, как мой recv получает данные, пока он возвращает 0 в первую очередь. И я хотел бы знать, что я делаю неправильно, чтобы возвращать данные с клиента/отправлять данные на сервер.
У вас проблема с приоритетом.
Эта:
if (numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0) == -1)
эквивалентно
if (numbytes = (recv(new_fd, buf, MAXDATASIZE-1, 0) == -1))
а также
recv(new_fd, buf, MAXDATASIZE-1, 0) == -1
0, когда recv
преуспевает.
Та же проблема присутствует на отправляющей стороне.
Нет причин писать такое неудобное и подверженное ошибкам условие.
Это безопаснее:
int numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0);
if (numbytes == -1)
perror("recv");
Вы должны проверить "numbytes" на ноль, отдельно, и если вы закроете его и выйдете из цикла чтения, потому что сверстник закрыл соединение. В противном случае, и предположим, что вы также протестировали -1, вам нужно обрабатывать только байты numbytes из буфера. Не все из них. В противном случае вы можете обработать уже обработанные байты. В этом случае это может означать восстановление строки с нулевым завершением буфера, или это может означать следующее:
printf("%.*s", numbytes, buf);
Вы печатаете любой мусор в буфере, выделенном стекем, а не то, что отправил клиент. Когда recv(2)
возвращает ноль, в поставляемый буфер ничего не помещается, поэтому это, вероятно, из предыдущей итерации цикла.
Заметки:
Connected TCP socket - это двунаправленный поток байтов. Это означает, что вы можете отправить несколько своих "сообщений" и получить их в одном фрагменте с другой стороны или наоборот. Прочтите из сокета в цикле до тех пор, пока у вас не будет достаточного количества данных для обработки, т.е. используйте явные разделители сообщений или предварительно отложите длину своего следующего сообщения. Это ваш протокол уровня приложения.
Не смешивайте строки C и C++ так. std::string
имеет метод size()
, используйте его вместо выполнения strlen( msgToSend.c_str() )
.
Выделение любых значительных буферов в стеке, особенно тех, кто получает вход от сети, является плохой идеей.
Печатание или иное прохождение дальше, непроверенный вход в сеть - это грубое нарушение безопасности, приводящее к возникновению любых проблем.
@molbdnilo ответ правильный. Я не заметил проблему приоритета в условных выражениях. Мои заметки все еще применяются.
std::string.length()
вместо size()
, это будет проблемой при отправке сообщения? И не могли бы вы разработать свою заметку 3? Вы имеете в виду buf[MAXDATASIZE]
?