C ++ Socket Recv смешанные сообщения

0

Привет, у меня проблемы с сервером сокетов и клиентом.

Проблема в том, что сообщения смешиваются, когда я отправляю их очень быстро. Когда я отправляю их, можно сказать, что 1 сообщение в секунду все работает хорошо, но когда я их обманывал 1 сообщение за 40 мс, они смешиваются.

вот мой код для получения:

std::string* AteneaClient::readSocket () {

std::string finalString = std::string("");
int size = MSG_SIZE;

bool receiving = true;
int timesBufferInc=0;
while (receiving) {
    std::string temporalString;

    //create an empty buffer
    char* RCV_BUFFER = (char*) malloc (size* sizeof(char));
    for(int i=0;i<size;i++){
        RCV_BUFFER[i]=' ';
    }
    RCV_BUFFER[size-1]='\0';

    int result =  recv(sock,RCV_BUFFER,size-1,NULL);
    if ( result== SOCKET_ERROR ) {
        free(RCV_BUFFER);
        return NULL;
    }
    else if(result<size-1){
        receiving=false;
    }

    temporalString = std::string(RCV_BUFFER);
    finalString+=temporalString;
}
return new std::string(finalString);

}

и вот мой код для отправки:

int sendThread(void* data){
SND_THREAD_DATA* parameters =(SND_THREAD_DATA*)data;
SOCKET* individualSocket = parameters->individualSocket;
std::string * message = parameters->message;

char RCV_BUFFER[MSG_SIZE];
std::string converter;
std::cout <<"(!)Thread: Iniciando sendThread Individual.."<<std::endl;
SOCKET default_socket = *individualSocket;

bool running=true;

while(running){


    int length=message->length();
    char *cstr = new char[length + 1];
    strcpy(cstr, message->c_str());
    if(::send(*individualSocket,cstr,length + 1,NULL)==SOCKET_ERROR){
        logSendError();
        running=false;
    }
    delete cstr;
    Sleep(SLEEPTIME);
}

}

и вот код, когда я установил сокет:

void AteneaClient::startUp(){
int iResult = 0;
iResult = WSAStartup(MAKEWORD(2, 2), &WinSockData);
if (iResult != NO_ERROR) {
    wprintf(L"(!)Main:WSAStartup() failed with error: %d\n", iResult);
    return;
}

ADDR.sin_addr.s_addr= inet_addr(IP);
ADDR.sin_family = AF_INET;
ADDR.sin_port = htons(PORT);
sock = socket(AF_INET,SOCK_STREAM,0);
running=true;

}

Кто-нибудь имеет представление, почему сообщения сокета смешиваются?

Благодарю!


РЕДАКТИРОВАТЬ:

это мой текущий метод приема с улучшениями от комментариев Максима:

std::string* AteneaClient::readSocket () {

int HEADER_SIZE=4;
std::string finalString = std::string("");
int sizeFirstBuffer = HEADER_SIZE*sizeof(char);
char* RCV_BUFFER=(char*) malloc(sizeFirstBuffer+1);

//clean new buffer
for(int i=0;i<HEADER_SIZE;i++){
    RCV_BUFFER[i]=' ';
    }
RCV_BUFFER[sizeFirstBuffer]='\0';



int result =  recv(sock,RCV_BUFFER,sizeFirstBuffer,NULL);
//cout << "The Size to read is:" <<RCV_BUFFER << endl;


//now i create a buffer with that size
int sizeThatIHaveToRead= atoi(RCV_BUFFER);
int sizeSecondBuffer = sizeThatIHaveToRead*sizeof(char);
char* RCV_BUFFER_SECOND=(char*) malloc(sizeSecondBuffer+1);

//clean new buffer
for(int i=0;i<sizeSecondBuffer;i++){
    RCV_BUFFER_SECOND[i]=' ';
    }
RCV_BUFFER_SECOND[sizeSecondBuffer]='\0';



result =  recv(sock,RCV_BUFFER_SECOND,sizeSecondBuffer,NULL);
//cout << "RCV_BUFFER_SECOND:" <<RCV_BUFFER_SECOND << endl;
finalString+=RCV_BUFFER_SECOND;
return new std::string(finalString);

}

  • 0
    Является ли сокет сокетом TCP ( SOCK_STREAM ) или UDP ( SOCK_DGRAM )? Это блокирующий или неблокирующий сокет?
  • 0
    это сокет TCP. SOCK_STREAM
Показать ещё 6 комментариев
Теги:
multithreading
sockets
winsock
winsock2

1 ответ

5
Лучший ответ

Вы отправляете строки через потоковые сокеты и ожидаете, что их будут отправляться и получать атомарно, например, ничто не отправляется/принимается, или вся строка не отправляется/не принимается. Это не то, как работают сокеты.

Потоковые сокеты часто отправляют только часть ваших данных, поэтому вам нужно продолжать отправку, пока все данные не будут отправлены. То же самое для получения.

Вам также необходимо как-то разграничить сообщения, иначе при получении вы не узнаете, когда сообщение закончится, а следующее запустится. Двумя наиболее распространенными способами являются: а) префиксные сообщения с их размером; б) использовать разделитель сообщений (например, символ новой строки).

ZeroMQ может выполнять обе эти задачи для вас: ваши приложения заканчивают отправку и получение полных сообщений, без необходимости внедрять кадрирование сообщений и отправку/получение на уровне байта.


Обновленный код по-прежнему неправильно использует вызовы send и recv.

Вот правильное использование с функциями для отправки и получения std::string

#include <stdexcept>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

ssize_t recv_all(int fd, void* buf, size_t buf_len) {
    for(size_t len = buf_len; len;) {
        ssize_t r = ::recv(fd, buf, len, 0);
        if(r <= 0)
            return r;
        buf = static_cast<char*>(buf) + r;
        len -= r;
    }
    return buf_len;
}

ssize_t send_all(int fd, void const* buf, size_t buf_len) {
    for(size_t len = buf_len; len;) {
        ssize_t r = ::send(fd, buf, len, 0);
        if(r <= 0)
            return r;
        buf = static_cast<char const*>(buf) + r;
        len -= r;
    }
    return buf_len;
}

void send_string(int fd, std::string const& msg) {
    ssize_t r;
    // Send message length.
    uint32_t len = msg.size();
    len = htonl(len); // In network byte order.
    if((r = send_all(fd, &len, sizeof len)) < 0)
        throw std::runtime_error("send_all 1");
    // Send the message.
    if((r = send_all(fd, msg.data(), msg.size())) < 0)
        throw std::runtime_error("send_all 2");
}

std::string recv_string(int fd) {
    ssize_t r;
    // Receive message length in network byte order.
    uint32_t len;
    if((r = recv_all(fd, &len, sizeof len)) <= 0)
        throw std::runtime_error("recv_all 1");
    len = ntohl(len);
    // Receive the message.
    std::string msg(len, '\0');
    if(len && (r = recv_all(fd, &msg[0], len)) <= 0)
        throw std::runtime_error("recv_all 2");
    return msg;
}
  • 0
    Я постараюсь отправить префиксное сообщение, как вы говорите, и вернусь к вам. Спасибо @ Максим Егорушкин
  • 0
    @chelo_c Другой вариант для вас - попробовать использовать zeromq . Он создает сообщения для вас через потоковые сокеты и многое другое.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню