C ++ Socket recv混合消息 [英] C++ Socket recv mixed messages

查看:137
本文介绍了C ++ Socket recv混合消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,我有一个套接字服务器和客户端的问题。

Hello i am having a problem with a socket server and client.

问题是,当我发送他们真的很快,消息混淆了。当我发送他们说,每秒一个消息每秒一切运行良好,但是当我每40毫秒他们1个消息,他们混淆了。

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 sned them 1 message per 40ms they get mixed up.

这里是我的代码接收:

here is my code for recieving:

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

}

这里是我设置套接字时的代码:

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;

}

套接字消息混淆了?

谢谢!

这是我目前收到的来自Maxim评论的改进方法:

this is my current recieve method with the improvements from Maxim comments:

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, e.g. 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.

您还需要以某种方式分隔消息,否则在接收时不会知道消息何时结束,下一个消息何时开始。两种最常见的方式是a)前缀消息的大小,b)使用消息分隔符(例如,换行符号)。

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 (e.g. new-line symbol).

ZeroMQ 可以为您执行这两项任务:您的应用程序最终发送和接收完整的消息,而无需实现消息成帧和在字节上发送/接收

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.

更新的代码仍然无法正确使用 send recv 呼叫。

The updated code still does not correctly use send and recv calls.

这是使用函数发送和接收 std :: string 的正确用法:

Here is correct usage with functions to send and receive a 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;
}

这篇关于C ++ Socket recv混合消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆