简体   繁体   English

C++ Socket recv 混合消息

[英]C++ Socket recv mixed messages

Hello I am having a problem with a socket server and client.您好,我的套接字服务器和客户端有问题。

The problem is that the messages get mixed up when I send them really fast.问题是当我非常快地发送消息时,消息会混淆。 When I send them lets say 1 message per second everything runs good, but when I send them 1 message per 40ms they get mixed up.当我向他们发送 1 条消息时,一切运行良好,但是当我每 40 毫秒向他们发送 1 条消息时,他们就会混淆。

here is my code for receiving:这是我的接收代码:

    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);
}

and here is my code for sending:这是我的发送代码:

    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);
    }

}

and here is the code when I set up the socket:这是我设置套接字时的代码:

    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;
}

Anyone has any idea why socket messages get mixed up?任何人都知道为什么套接字消息会混淆?

Thanks!谢谢!


EDIT:编辑:

this is my current receive method with the improvements from Maxim comments:这是我目前使用 Maxim 评论改进的接收方法:

    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);
}

You are sending strings through stream sockets and expect them to be sent and received atomically, eg either nothing is sent/received or the entire string is sent/received.您正在通过流套接字发送字符串,并期望它们以原子方式发送和接收,例如,要么没有发送/接收任何内容,要么发送/接收整个字符串。 This is not how stream sockets work.这不是流套接字的工作方式。

Stream sockets often send only part of your data, so you need to keep sending until all data has been sent.流套接字通常只发送您的部分数据,因此您需要继续发送,直到所有数据都发送完毕。 Same is for receiving.接收也是一样。

You also need to delimit the messages somehow, otherwise when receiving you won't know when a message ends and the next one starts.您还需要以某种方式分隔消息,否则在接收时您将不知道消息何时结束而下一条消息何时开始。 The two most common ways are a) prefix messages with their size, b) use a message delimiter (eg new-line symbol).两种最常见的方式是 a) 使用消息大小作为前缀,b) 使用消息分隔符(例如换行符)。

ZeroMQ can do both of these tasks for you: your applications end up sending and receiving complete messages, without you having to implement message framing and sending/receiving on byte level. ZeroMQ可以为您完成这两项任务:您的应用程序最终会发送和接收完整的消息,而无需在字节级别实现消息帧和发送/接收。


The updated code still does not correctly use send and recv calls.更新后的代码仍然没有正确使用sendrecv调用。

Here is correct usage with functions to send and receive a std::string :以下是发送和接收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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM