如何使用 QTcpSocket 读取超过 8192 字节?

Posted

技术标签:

【中文标题】如何使用 QTcpSocket 读取超过 8192 字节?【英文标题】:how to read more than 8192 byte with QTcpSocket? 【发布时间】: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 之外的方式完成(即提前知道多少字节或分隔符)。 【参考方案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);

    


【讨论】:

以上是关于如何使用 QTcpSocket 读取超过 8192 字节?的主要内容,如果未能解决你的问题,请参考以下文章

QTcpSocket 读取错误

QTcpSocket,无法读取传入数据

如何正确确定 QTCPSocket 中的输入结束?

读取 QTcpSocket

QTcpSocket同步读取

QTcpSocket 从服务器接收数据