Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Receiving incomplete data: How to control?  (Read 3751 times)

0 Members and 1 Guest are viewing this topic.

VinceLaTaupe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Receiving incomplete data: How to control?
« on: July 11, 2017, 01:39:52 pm »
Hi everyone.
Thank you by advance for your help !

I have an issue and I don't know the cause.
J'ai un problème dont je n'arrive pas à identifier tout à fais la cause. First of all, I can not use the sf :: Packet class because I do not handle the "server side".

I am supposed to receive a generic message of about 60 bytes.

So I created a buffer of size 64. The problem is that at the reception I do not get the 61bytes, at least not all the time and that's what I do not understand ...
Sometimes I get the whole message, sometimes not.

The problem is that when I do not receive the whole message, the status returned is still sf::Socket::Done, therefore, no way for me to analyze whether my message is complete or not to re-call the receive() function ...

Here is my code "abbreviated" and the associated answers:

int main()
{
        sf::TcpSocket socket;
        std::cout << "Connexion" << std::endl;
       
        sf::Socket::Status status = socket.connect("192.168.127.254", 9001);
        std::cout << status << std::endl;

        size_t received(1);
        char data[64] = { 0 };
        std::string str{ "" };

        str =  "#1Z1|\r" ;

        if (socket.send(&str[0], str.size()) != sf::Socket::Done)
                std::cout << "ERROR sending" << std::endl;
        else
                std::cout << "Message sent : " << str << std::endl;

        status = socket.receive(data, 64, received);

        if ( status != sf::Socket::Done)
                std::cout << "ERROR reception. Status : " << status << std::endl; // Just for illustration
        else
        {
                data[received - 1] = '\0';
                str = data;
                std::cout << "Message received: " << str << " (" << received << ")" << std::endl;
                std::cout << "Status : " << status << std::endl;
        }

        // To prove that there are still some:
        if (received != 61)
        {
                status = socket.receive(data, 64, received);

                if (status != sf::Socket::Done)
                        std::cout << "ERROR reception. Status : " << status << std::endl; // Just to illustrate
                else
                {
                        data[received - 1] = '\0';
                        str = data;
                        std::cout << "Message received : " << str << " (" << received << ")" << std::endl;
                        std::cout << "Status : " << status << std::endl;
                }
        }
}
 

Here are the results in the windows console, first when it works properly and sencondly when it doesn't :

(click to show/hide)


Status 0 correspond to sf::Socket::Done.

You see well that sometimes I do not get everything, and yet the program returns me a Done status ...

An idea of the problem and how to solve it?

Thanks by advance,
Vincent.

PS : I'm beginner, sorry if I made big mistake :p

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Receiving incomplete data: How to control?
« Reply #1 on: July 11, 2017, 02:24:58 pm »
This is very well explained in the socket tutorial:
Quote
The last difference is about the way data is transported. TCP is a stream protocol: there's no message boundary, if you send "Hello" and then "SFML", the remote machine might receive "HelloSFML", "Hel" + "loSFML", or even "He" + "loS" + "FML".

So you have to find a way to detect the end of the message within the received stream of data. If the communication protocol has no concept of boundaries, then there's no other choice but to rely on the number of bytes received.
Laurent Gomila - SFML developer

VinceLaTaupe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Receiving incomplete data: How to control?
« Reply #2 on: July 11, 2017, 02:38:09 pm »
This is very well explained in the socket tutorial:
Quote
The last difference is about the way data is transported. TCP is a stream protocol: there's no message boundary, if you send "Hello" and then "SFML", the remote machine might receive "HelloSFML", "Hel" + "loSFML", or even "He" + "loS" + "FML".

So you have to find a way to detect the end of the message within the received stream of data. If the communication protocol has no concept of boundaries, then there's no other choice but to rely on the number of bytes received.

I forgot this one ...

Well I can't predict the number of bytes received ...
As is I'm not sure there is a special incomming communication protocol, I'll check this way.

But I think that the last byte sent is the carriage return "\r". But not sure I can detect it with something like :
if (data[received-1] != '\r')
//receive again and again
 

This character is always the last one no ?

Thank you for you response Laurent.

VinceLaTaupe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Receiving incomplete data: How to control?
« Reply #3 on: July 11, 2017, 03:01:17 pm »
Fastest resolved problem ever !

It works perfectly, just needed a little do{}while() loop ...

Quite easy, sorry for bothering...

My code for those who'd like :

bool status = false;
        int i(0);
        do {
                socket.receive(data, 64, received);

                if (data[received - 1] != '\r')
                {
                        str += data;
                        status = false;
                }
                else
                {
                        data[received - 1] = '\0';
                        str += data;
                        status = true;
                }
                ++i;
        } while (statut == false);
       
        std::cout << "Message received in " << i << " times: \n" << str << std::endl;
 


Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Receiving incomplete data: How to control?
« Reply #4 on: July 11, 2017, 03:25:06 pm »
Yes, text protocols often use end-of-line characters such as \r and/or \n.

So you've got the right solution, except that it is not robust. Assuming that \r will always be the last character of a chunk of received data is wrong, it may be anywhere within the stream; and this may actually happen if you start receiving multiple messages with very short delay between them.

The general approach is:
- concatenate all the received bytes in a buffer
- search for the message delimiter (\r in your case)
- extract all bytes up to this position: this is your message
- leave the rest in the buffer: this is the start of the next message
Laurent Gomila - SFML developer

VinceLaTaupe

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Receiving incomplete data: How to control?
« Reply #5 on: July 11, 2017, 03:34:40 pm »
Got it !

However in this case I cannot receive multiple messages because of my structure : My program communicate with a controller card. Therefore the controller responds a simple message only when I ask him to.

But I'll try to do as you said just to practice !

Thank you again Laurent !