[RESOLVED] Winsock recv split data

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

[RESOLVED] Winsock recv split data

Post 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.
Last edited by LunaRebirth on Sun Feb 19, 2017 7:33 pm, edited 1 time in total.
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Winsock recv split data

Post 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
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Winsock recv split data

Post 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.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Winsock recv split data

Post by thanhle »

You need to send the length of your data in bytes and process your struct based on that length.
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Winsock recv split data

Post 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 "";
    //...
}
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Winsock recv split data

Post 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
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: [RESOLVED] Winsock recv split data

Post 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
Post Reply