如何在QTcpSocket中读取完整数据?

时间:2013-11-29 14:47:35

标签: c++ qt qt5 qtcpsocket

现在服务器(用java实现)会向我发送一些流数据,我的代码如下:

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

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

但我发现即使服务器发给我一个只有几个字符的字符串,数据被截断,我的函数被调用两次,因此temp是我想要的永远完整的数据。
如果服务器发给我一个更长的字符串,我的函数可能会被调用三次或更多次,这使我无法知道数据完全被传输的时间。
所以任何人都可以告诉我如何轻松完全接收数据,没有这么多困扰的步骤?如果这与其他一些问题重复,我很抱歉,我无法让他们的答案适合我。非常感谢!

4 个答案:

答案 0 :(得分:12)

您所看到的是客户端 - 服务器通信的正常现象。数据以数据包形式发送,readyRead信号通知您的程序有可用的数据,但没有关于数据的数据或数据的概念,因此您必须处理此问题。

要正确读取数据,您需要一个缓冲区,如@ratchetfreak所述,在从流中读取字节时附加字节。了解所发送数据的格式非常重要,以便知道何时有完整的消息。我之前使用过至少两种方法来做到这一点: -

1)确保发送的消息以正在发送的消息的大小(以字节为单位)开头。在接收数据时,首先要读取大小,然后继续追加缓冲区,直到它达到预期的大小。

2)以已知格式发送所有数据,例如JSONXML,可以检查消息的结尾。例如,在JSON的情况下,所有数据包将以一个左括号'{'开头,以一个右括号'}'结束,因此您可以计算大括号并匹配数据,或使用QJsonDocument :: fromRawData来验证数据已经完成。

使用这两种方法后,我建议使用第一种方法;包括正在发送的消息的大小。

答案 1 :(得分:2)

如果所有数据尚未到达,那么您的while循环将提前退出。您需要使用一种消息格式,让接收代码确定何时收到完整的消息。例如,消息可以以长度元素开头,或者如果您正在处理文本,则消息可能以某些字符作为终结符结束。

答案 2 :(得分:2)

您可以使用缓冲区字段暂时保存未完成的数据,并在完成后处理数据包:

{
    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);
        }
    }
}

答案 3 :(得分:1)

问题是在tcp期间数据传输数据是以未定义的块发送的。如果您正在尝试读取已定义的块大小,则必须事先知道预期的块大小,以便确定块何时结束(类似于零终止的c-string)。

检查this answer是否对您没有帮助(有一个等待预期数据块的技巧)。