【问题标题】:How to read complete data in QTcpSocket?如何在 QTcpSocket 中读取完整的数据?
【发布时间】:2013-12-15 19:10:46
【问题描述】:

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

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

read_from_server()

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

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

【问题讨论】:

    标签: c++ qt qt5 qtcpsocket


    【解决方案1】:

    您所看到的对于客户端-服务器通信来说是正常的。数据以数据包的形式发送,readyRead 信号通知您的程序有数据可用,但不知道有什么或有多少数据,因此您必须处理这个问题。

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

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

    2) 以已知格式发送所有数据,例如JSONXML,可以检查消息的结尾。例如,在 JSON 的情况下,所有数据包都将以左大括号“{”开头并以右大括号“}”结尾,因此您可以计算大括号并匹配数据,或者使用 QJsonDocument::fromRawData 来验证资料齐全。

    这两种方法都用过,我推荐用第一种;包括正在发送的消息的大小。

    【讨论】:

    • 关于“2”,如果对象包含带大括号的字符串,计算大括号将是一个问题。最好尝试正确解析它,如果失败则假设它不完整。
    • 我完全同意,您需要考虑到这一点并检查字符串,尽管我确实提到使用 QJsonDocument 来验证数据。感谢您强调这一点;O)
    • @Merlin069 感谢您的体验!
    • @TheDarkKnight 如果我要将 JSON 数据包从 PHP 发送到与服务器应用程序连接的套接字。我是否必须继续向 QByteArray 添加字节,直到检查所有字节加在一起是否等于 QJsonDocument 的检查成功?我已经在这个套接字流媒体上待了几天了,在你掌握它之前它非常复杂。
    • @CantThinkOfAnything 简单的回答:是的。但是,您可以发送单个 Json 对象并检查它们是否完整,为每个对象构建 QJsonDocument,但您最好还是坚持先在字节数组中构建整个文档。
    【解决方案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】:

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

      【讨论】:

      • 谢谢,我会要求服务器附加一个结束字符:)
      【解决方案4】:

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

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

      【讨论】:

      • 感谢分享 :) 就像你说的那样,我会找到一些方法来确定块何时结束
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多