у меня есть программа сервера-клиента протокола TCP.
В отличие от многих людей, я не получаю ошибок, потому что моя функция отправки не отправляет столько байтов, сколько должна.
Моя проблема в том, что функция recv () ловит кучу странных символов. Я зашифровал их, и они, как правило, либо отрицательные числа (я думаю, больше, чем 4 бита), либо не алфавитно-цифровые (то, что появляется постоянно = \ 8 = ◘).
Я использую следующие функции:
bool Socket::Send(char* msg){
if ((send(sockfd, msg, strlen(msg), 0)) == SOCKET_ERROR){
Close();
return false;
}
return true;
}
int Socket::Receive(char* msg, int maxlen){
int recvResult;
if ((recvResult = recv(sockfd, msg, maxlen, 0)) == SOCKET_ERROR){
Close();
}
return recvResult;
}
Я проверил, и все отправляемое в порядке. Я имею в виду, я написал это в файл и проверил это, и это было хорошо.
Есть что-нибудь еще, что я должен рассмотреть? Что я делаю неправильно?
В отличие от многих людей, я не получаю ошибок, потому что моя функция отправки не отправляет столько байтов, сколько должна.
Никто не получает эту ошибку, потому что она никогда не происходит, хотя, поскольку вы не проверяете ее, вы не можете утверждать, что ее не происходит.
Моя проблема в том, что функция recv () ловит кучу странных символов.
Нет. Что происходит, так это то, что recv()
функция возвращает меньше байтов, чем запрошено, и это происходит из-за того, что не указано, что нужно передавать более одного байта или ноль байтов в неблокирующем режиме. Вы должны зацикливаться, пока не прочитаете все данные, которые вы ожидаете.
И вы должны позаботиться о том, чтобы не использовать байты в буфере приема, которые не были переданы в самый последний recv()
вызов, как указано его возвращаемое значение.
Вы почти наверняка печатаете весь буфер и видите мусор. Он не был ни отправлен, ни получен.
NB, если recv()
возвращает ноль, вы должны закрыть сокет.
Вы сказали, что у вас есть протокол TCP, но у вас есть не протокол, а просто TCP-соединение.
Для реализации протокола вам необходимо отправить дополнительную информацию, часть recv () должна (должна) знать, что получит.
Вам нужно отправить либо впереди длину буфера, либо завершающий символ в конце буфера, который не должен быть частью остальной части отправленного сообщения. Такие символы, как перевод строки (10), возврат каретки (13) и перевод строки (12), являются хорошими кандидатами.
Если вы решите использовать завершающий символ, то вы должны читать (recv) по одному символу за раз, проверяя, является ли это завершающим индикатором. Завершающие символы полезны только при отправке строк, которые представляют собой буквенные слова, не указывается для использования для отправки файлов или изображений или двоичных строк.
Я изменил ваши подпрограммы, реализуя длину метода индикатора буфера:
bool Socket::Sender(char* msg){
// Send a string with the length (int) of it ahead
int len = strlen(msg);
int hLen = htonl(len); // put it in network byte order
if (send(sockfd, (char *) &hLen, sizeof(int), 0) == sizeof(int) &&
send(sockfd, msg, len, 0) == len)
{
return true;
}
Close();
return false;
}
int Socket::Receive(char* msg, int maxlen){
int recvResult;
int len;
int offset;
// receive a string with the length (int) of it first
if (recv(sockfd, (char *) &len, sizeof(int), 0) == sizeof(int))
{
len=ntohl(len); // put in host byte order
// Check there is enough space
if (len > maxlen)
{
// the receive chars is bigger than maxlen,
// either receive as many as maxlen or return error
len=maxlen;
// Close();
// return -1;
}
offset=0;
// loop until len chars are received, no more no less
while (offset < len)
{
recvResult = recv(sockfd, (char *) &msg[offset], len-offset, 0);
if (recvResult <= 0)
{
Close();
return -1;
}
offset +=recvResult;
}
// Succeeded, return len
return len;
}
Close();
return -1;
}