Page 1 of 1

[RESOLVED] Winsock recv split data

Posted: Sun Feb 19, 2017 12:01 am
by LunaRebirth
Hey guys, this is a super strange question because I've never experienced this before.

Code: Select all

void Server::ClientThread( int myID ) {
    printf("ClientThread\n");
    bool running = true;
    while (running) {
        Server::clients[myID]->getMessage();
 
        if (myID == 0)
            Server::clients[myID]->sendMessage("You are client #1");
        else
            Server::clients[myID]->sendMessage("You are not client #1");
 
        Server::clients[myID]->sendMessages();
    }
}
 
bool Server::getNewConnection() {
    int sin_size = sizeof(struct sockaddr_in);
    socklen_t temp=sin_size;
 
    sockaddr clients_addr;
 
    fd_set readSet;
    FD_ZERO(&readSet);
    FD_SET(server_skt, &readSet);
    timeval timeout;
    timeout.tv_sec = 0;  // Zero timeout (poll)
    timeout.tv_usec = 0;
    if(select(server_skt, &readSet, NULL, NULL, &timeout) == 1) {
 
        if ( (client_skt = accept(server_skt, &clients_addr, &temp))!=-1) {
            Server::clients.push_back(new Client(client_skt));
            CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Server::ClientThread,(PVOID)Server::clients.size()-1, NULL, NULL);
 
            return true;
        }
    }
    return false;
}
So basically what's happening is in my main loop, I'm calling Server::getNewConnection() which checks for a new, you guessed it, connection. If a new client joins, a thread is created and ran.

My Server::getMessage() uses recv() to wait for data, it is blocking.
But for some reason, the data I'm getting is being split twice and inaccurately.

I am sending a struct like so:

Code: Select all

struct dataStruct {
     char message[SERVER_MAXLEN+1];
     int messageID;
     int AoMessages;
     int ok;
};
dataStruct SD;
 
void Client::sendMessages() {
    //...
 
    send(this->getSocket(),reinterpret_cast<char *>(&SD),sizeof(SD),0);
 
    //...
}
And similarly receiving a message like:

Code: Select all

struct dataStruct {
     char message[SERVER_MAXLEN+1];
     int messageID;
     int AoMessages;
     int ok;
};
dataStruct RD;
 
void Client::getMessage() {
    //...
 
    recv(this->getSocket(),reinterpret_cast<char *>(&RD),sizeof(RD),0);
 
    //...
}
After using recv, my Server::ClientThread gets a message twice in a row (loops twice, waits for data, loops twice, waits for data, ...)
but the information I receive is like this:

Code: Select all

First recv:
messageID = 0
AoMessages = 0
ok = 0
message = "Message OK"
 
Second recv:
messageID = 10
AoMessages = 10
ok = 1
message = ""
When there should only be 1 recv, not two, that looks like this:

Code: Select all

What it should be:
messageID = 10
AoMessages = 10
ok = 1
message = "Message OK"
I feel like this instance is abnormal and I've never crossed it before, just wanted to see if anyone had some suggestions since I'd been trying to figure out why it's doing this for the past 2 hours.

Re: Winsock recv split data

Posted: Sun Feb 19, 2017 12:12 am
by LunaRebirth
Add:
The client only sends data once, I've checked.
The server receives split twice.

Note:
I have also tried using a function to wait for all data like:

Code: Select all

ssize_t Client::sendAll(int sockfd, const void *buf, size_t len, int flags) {
   ssize_t result;
   char *pbuf = (char *)buf;
   while ( len > 0 ) {
     result = send(sockfd,pbuf,len,flags);
     if ( result <= 0 ) break;
     pbuf += result;
     len -= result;
   }
   return result;
}
 
ssize_t Client::recvAll(int sockfd, const void *buf, size_t len, int flags) {
    ssize_t result;
   char *pbuf = (char *)buf;
   while ( len > 0 ) {
     result = recv(sockfd,pbuf,len,flags);
     if ( result <= 0 ) break;
     pbuf += result;
     len -= result;
   }
   return result;
}
with the same results

Re: Winsock recv split data

Posted: Sun Feb 19, 2017 3:49 am
by CuteAlien
Ugh, been a few years since I used sockets directly, but some things which maybe could affect it:

Check return values of recv to see how many bytes you really received. You can also enforce it to wait until you get as many bytes as you specified with MSG_WAITALL as last parameter.

Not sure how your scopes look like. For example if you have more than one thread and they all access dataStruct SD; then they could conflict with each other.

Be careful when using structs without packing for network, generally better to set packing to 1 (check irrpack.h to see how to do that with different compilers). But likely not your problem here (as the size is still the same on both sides).

You shouldn't really need a reinterpret_cast. It's the most dangerous cast as it forces the compiler to re-interpret some variable memory as another type, which is only necessary in very specific use-cases (generally used for more advanced tricks). When static_cast has a problem it often is a sign that you have a real problem which you should not ignore.

Re: Winsock recv split data

Posted: Sun Feb 19, 2017 3:47 pm
by thanhle
You need to send the length of your data in bytes and process your struct based on that length.

Re: Winsock recv split data

Posted: Sun Feb 19, 2017 4:29 pm
by LunaRebirth
I tried using MSG_WAITALL (0x8) on my recvAll function. No change. When I check the return for how many bytes I've received, both split structs return the correct amount of data.
Another thing to add is that this also occurs when there is only one thread running, so that shouldn't be an issue.

Same results for this instead:

Code: Select all

Server::sendAll(sock,(char*)(&SD),sizeof(SD),0);
 
//...
 
char* Server::getMessage() {
    Server::dataStruct RDTemp;
    recvAll(sock, (char*)(&RDTemp), sizeof(RDTemp), 0);
    if (RDTemp.ok != 1)
        return "";
    //...
}

Re: Winsock recv split data

Posted: Sun Feb 19, 2017 4:45 pm
by LunaRebirth
Strange. Now my results are all over the place like:

Code: Select all

messageID = 744975983
AoMessages = 544498024
ok = 1814066025
message = "Message OK"
The above gives really high incorrect values almost a dozen times (with the correct message) until I get the full correct information.
I'd say for every 10 recv's, 1 of them is correct

Re: [RESOLVED] Winsock recv split data

Posted: Sun Feb 19, 2017 7:35 pm
by LunaRebirth
Meh.
I decided to take a project server/client I was working on and take pieces of the code from it instead.
Seems like a replica of what I was already doing with receiving and sending structs, but somehow the code from my previous project doesn't have these issues.

Anyways thanks dudes