Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read complete data in QTcpSocket?

Now the server (implemented with java) will send some stream data to me, my code is like below:

connect(socket, SIGNAL(readyRead()), this, SLOT(read_from_server()));

in the read_from_server():

{
    while (socket->bytesAvailable())
    {
        QString temp = socket->readAll();
    }
}

but I find that even the server sent me a string with only several characters, the data is truncated, and my function is called twice, thus temp is the never complete data that I want.
If server send me a longer string, my function may be called three or more times, making me diffficult to know at which time the data is transfered completely.
So anyone can tell me how to completely receive the data easily, without so many steps of bothering? I'm sorry if this is duplicated with some questions else, I couldn't get their answers work for me. Many thanks!

like image 997
yakiang Avatar asked Nov 29 '13 14:11

yakiang


3 Answers

What you're seeing is normal for client-server communication. Data is sent in packets and the readyRead signal is informing your program that there is data available, but has no concept of what or how much data there is, so you have to handle this.

To read the data correctly, you will need a buffer, as mentioned by @ratchetfreak, to append the bytes as they're read from the stream. It is important that you know the format of the data being sent, in order to know when you have a complete message. I have previously used at least two methods to do this: -

1) Ensure that sent messages begin with the size, in bytes, of the message being sent. On receiving data, you start by reading the size and keep appending to your buffer until it totals the size to expect.

2) Send all data in a known format, such as JSON or XML, which can be checked for the end of the message. For example, in the case of JSON, all packets will begin with an opening brace '{' and end with a closing brace '}', so you could count braces and match up the data, or use QJsonDocument::fromRawData to verify that the data is complete.

Having used both of these methods, I recommend using the first; include the size of a message that is being sent.

like image 95
TheDarkKnight Avatar answered Nov 16 '22 09:11

TheDarkKnight


you can use a buffer field to hold the unfinished data temporarily and handle packets as they complete:

{
    while (socket->bytesAvailable())
    {
        buffer.append(socket->readAll());
        int packetSize = getPacketSize(buffer);
        while(packetSize>0)
        {
            handlePacket(buffer.left(packetSize);
            buffer.remove(0,packetSize);
            packetSize = getPacketSize(buffer);
        }
    }
}
like image 3
ratchet freak Avatar answered Nov 16 '22 08:11

ratchet freak


If all of the data has not yet arrived then your while loop will exit prematurely. You need to use a message format that will let the receiving code determine when the complete message has been received. For example, the message could begin with a length element, or if you are dealing with text the message could end with some character used as a terminator.

like image 2
ScottMcP-MVP Avatar answered Nov 16 '22 08:11

ScottMcP-MVP