【问题标题】:how to read more than 8192 byte with QTcpSocket?如何使用 QTcpSocket 读取超过 8192 字节?
【发布时间】:2019-09-25 10:44:47
【问题描述】:

我向服务器发送请求并得到响应我的代码是这样的:

QString mywindow::SocketCommunication(QString JsonRequest)
{
    QTcpSocket *socket = new QTcpSocket(this);
    QString result;
    socket->connectToHost(SOCKET_IP, SOCKET_PORT);//SOCKET_IP and SOCKET_PORT are defined constants and are correct

    if (socket->waitForConnected(-1) && socket->state() == QAbstractSocket::ConnectedState)
    {

        if (socket->write(JsonRequest.toLatin1()) == -1)
        {

            socket->disconnectFromHost();
            result = "Could not send message";
        }
        else
        {
            socket->flush();


            if (!socket->waitForReadyRead(90000))
            {
                socket->disconnectFromHost();
                result = "tcp con timeout for reading";
            }
            else
            {
                QByteArray JsonResponse = socket->readAll();// the problem is here

                socket->close();

                JsonResponse = JsonResponse.trimmed();
                QString jsonResp = QString::fromStdString(JsonResponse.toStdString());

                result = ParseResponse(jsonResp) // here i parse the response. it works fine and is not important in this question.
            }
        }
    }

    else
    {
        qDebug() << "cannot connect";
        socket->disconnectFromHost();
        result = "Could not Connect to Server";
    }
    return result;
}

现在,当来自服务器的响应小于 8192 字节时,它可以正常工作。否则这只读取前 8192 个字节。当我在阅读所有内容后输入socket-&gt;error() 时,我得到-1,即 QAbstractSocket::UnknownSocketError。你知道为什么会发生这种情况吗?我应该如何补救?

ps:我认为问题不在于 QAbstractSocket::DatagramTooLargeError,它是

数据报大于操作系统的限制(可以低至 8192 字节)。

因为我可以发送超过 8192 并且其他程序可以与更大的消息进行通信。

【问题讨论】:

  • 多次调用阅读?无论如何,您都必须使用 TCP 来执行此操作,因为由于它是一个流式协议,因此没有包或开始或结束。一次接收可以为您提供少于一条消息、一条完整消息或多条消息。
  • 你的意思是一会儿socket-&gt;read(4096)?那这段时间应该是什么条件呢?
  • 多次调用读取写入。显示的代码似乎没有完全检查 write() 的返回值,因此,可能实际上并没有写出所有内容,这取决于 Qt 的 bezerkeley 套接字包装器的工作方式。 “其他程序”可以发送和接收更多内容的原因是因为它们实际上了解从套接字读取和写入的工作原理,并且可能不会读取或写入所有内容,因此它们被专门编码为具有尝试 agan 的逻辑,直到一切都完全读和写。
  • 您需要在 TCP 之上提出一个协议,以某种方式告诉您需要接收多少。这可以通过使用包含要接收的数据长度的固定大小的消息头来完成,或者通过使用您检查的特定消息或“包”分隔符来完成。或者,像旧的 HTTP 一样,一直读取到连接被另一端关闭。
  • DataGram 是 UDP 概念,而不是 TCP。您需要了解 TCP 在数据包中不起作用。它是一种流式协议:你会得到一个或多个数据块,突飞猛进。您无法控制块的大小;每个都可能不同;您负责自己组装这些块(它们已正确排序)。您还需要知道数据何时通过 TCP 之外的方式完成(即提前知道多少字节或分隔符)。

标签: c++ qt qtcpsocket


【解决方案1】:

如果当前值太小,您可能需要将 QAbstractSocket::setReadBufferSize() 设置为更大的值。但这是一个内部 Qt 缓冲区,默认情况下应该足够大。很可能您需要设置QAbstractSocket::ReceiveBufferSizeSocketOption,这是一个操作系统级别的套接字选项。请参阅 QAbstractSocket::socketOption() 和 QAbstractSocket::setSocketOption()

【讨论】:

    【解决方案2】:

    这里的问题是socket-&gt;write() 是一个相对低级的操作,它是QIODevice API 的一部分。它不会将您的整个数据拆分为

    希望您可以利用QDataStream 轻松发送/接收数据,而无需考虑协议实现:

    //send data
    QDataStream sender(socket);
    QByteArray dataWhichMightBeBiggerThan8192Bytes = jsonRequest.toLatin1();
    sender << dataWhichMightBeBiggerThan8192Bytes;
    

    接收数据:

    //connect your socket
    QObject::connect(
        socket, &QIODevice::readyRead,
        this, &mywindow::_processIncomingData
    );
    

    那么,在你的课堂上:

    //Is called every time new data is sent to the socket 
    void mywindow::_processIncomingData() {
    
        //prepare to receive data 
        QDataStream receiver(this->_innerSocket); 
    
        //will loop until the whole waitingBytes of the socket are exhausted 
        while(!receiver.atEnd()) { 
    
            //start a transaction, so the waitingBytes of the socket can be automatically reset if not all the expected data is there 
            receiver.startTransaction();
    
            //push waitingBytes into a QByteArray
            QByteArray myJsonAsLatin1;
            receiver >> myJsonAsLatin1;
    
            //commit : if it failed, means data is missing, so you may keep looping while the client downloads more
            if(auto commitFailed = !receiver.commitTransaction()) continue;
    
            //commit succeeded, waitingBytes are freed from your QByteArray, you can now process your data
            this->_useMyData(myJsonAsLatin1);
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-08-24
      • 2015-03-16
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2017-02-03
      • 1970-01-01
      • 2013-11-09
      • 1970-01-01
      相关资源
      最近更新 更多