Advertisement

data is losing with sdl_net and tcp. please help me

Started by May 26, 2018 06:23 PM
2 comments, last by Emre Kaya 6 years, 6 months ago

im sending data from server.exe like this

for(int i=0;i<10;i++)
{      
  sprintf( buffer,"%d",i);
  SDLNet_TCP_Send(clientSocket, buffer, strlen(buffer)+1);    
}

from client.exe

if i use this:

while(1)
{
    if(SDLNet_CheckSockets(socketSet,0)>0)
    {
        if(SDLNet_SocketReady(clientSocketTCP)>0)
        {
           int RecvSizeResult=SDLNet_TCP_Recv(clientSocketTCP, buffer, 5000);
           cout<<"RecvSizeResult= "  << RecvSizeResult <<endl;
           if(RecvSizeResult>0)
           {
              cout<<"buffer= " <<buffer <<endl;
           }

        }
    }
}

and i am taking this result:

RecvSizeResult = 11

buffer = 0

0 is my first message after that i cant take any other messsages

and i tried another way in client.exe like this :

while(1)
{
    if(SDLNet_CheckSockets(socketSet,0)>0)
    {
        if(SDLNet_SocketReady(clientSocketTCP)>0)
        {
           while(1)
           {
              int RecvSizeResult=SDLNet_TCP_Recv(clientSocketTCP, buffer, 5000);
              cout<<"RecvSizeResult= "  << RecvSizeResult <<endl;
              cout<<"buffer= " <<buffer <<endl;
              if(RecvSizeResult<=1)
              {
                 break;
              }
           }


        }
    }
}

this time i generally took same result but sometimes i am taking 2 messages but not all . like this:

RecvSizeResult = 11

buffer = 0

RecvSizeResult = 4

buffer = 7

my question is how can i take all messages? like this:

buffer=0 buffer=1 buffer=2 buffer=3 ... buffer=9

You're making the assumption that one "send" corresponds with one "receive". This is not true.

Network data sent with "send" calls is merged into a long stream, then packetized for transfer, where each packet is routed across the network (where it may get lost or discarded and sent again, etc). Packets that arrive at the receiving end are then re-assembled in the correct order so you get your stream again, which is then given to "receive" calls in arbitrary blocks.

This means that there is no relation between "send" calls and "receive" calls other than all the data that you sent will get received in the same order.

One "receive" may contain several "sends", or you may get only partly "send" data (where you get more of that sent text on the next "receive" call), or anything in-between. To get the message again, you have to read the data from the network into a buffer, and then detect where the messages end.

Untested code goes like something below.


int end = 0; // Index of first free space in the buffer.
while (true) {
  // Append new data at the end of the previous remaining data
  int received = SDLNet_TCP_Recv(clientSocketTCP, buffer + end, 5000 - end);
  // handle errors etc

  end = end + received;
  while (true) {
    // detect a message at the start of the buffer
    int index = 0;
    while (index < end && buffer[index] != '\0') {
      index = index + 1;
    }
    if (index >= end) { // Failed to find a message, wait for more data
      break;
    }
    
    // 'index' points to the '\0', the last byte of the message
    int length = index + 1;
    
    // buffer[0] to buffer[index] is a message
    printf("Found a message of length %d\n", length);
    
    // Remove message from the buffer (by moving everything after it)
    memmove(buffer, buffer + length, end - length);
    end = end - length;
    
    // and try to find the next message
  }
}

The 'buffer' contains a bit remaining data from the previous call (buffer[0] to buffer[end] exclusive). You append new data from the network behind it, and then try to find messages in the buffer by detecting their end (which in your case is easy, since '\0' can only happen at the end of the message). When you find a message, you can do something with it like printing its length. You continue finding messages until you fail to detect a message. Some data from the next message may still be present in the buffer, that will be the "remaining data from the previous call" I mentioned above.

This code isn't very efficient, memmove is an expensive and quite unneeded call here. It's here so each message can be found starting at buffer[0]. If you extend to allowing a message to start at buffer, the only text you have to move is the partial last received bytes that do not yet form a complete message.

Advertisement

thank you so much. now i knew what is it "receive" and i can fix my code in the way you suggest.

This topic is closed to new replies.

Advertisement