How to read complete data in QTcpSocket?

2020-02-12 07:28发布

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!

4条回答
等我变得足够好
2楼-- · 2020-02-12 07:42

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.

查看更多
等我变得足够好
3楼-- · 2020-02-12 07:45

Problem is that during tcp data transfer data are send in undefined chunks. If you are trying to read defined block size you have to know in advance expected chunk size ore have a way to determinate when your block ends (something like zero terminated c-string).

Check if this answer doesn't help you (there is a trick to wait for expected data block).

查看更多
4楼-- · 2020-02-12 07:52

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.

查看更多
【Aperson】
5楼-- · 2020-02-12 08:09

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);
        }
    }
}
查看更多
登录 后发表回答