QTcpSocket 数据传输在读取缓冲区已满时停止,并且在释放时不会恢复

QTcpSocket data transfer stops when read buffer is full and does not resumes when it frees up

我有服务器-客户端 Qt 应用程序,其中客户端向服务器发送数据包,服务器以设定的时间间隔读取它们。碰巧客户端发送数据的速度比服务器读取数据的速度快,从而填满了服务器端的所有内存。我正在使用 QAbstractSocket::setReadBufferSize(size) 在服务器端设置最大读取缓冲区大小,当它填满时,套接字数据传输停止,数据在客户端缓冲,这是我想要的,但问题是当服务器的 QTcpSocket 的 内部读取缓冲区释放(不再满)时,客户端和服务器之间的数据传输不会恢复。

我试过使用 QAbstractSocket::resume() 这似乎有效,但 Qt5.10 文档说:

Continues data transfer on the socket. This method should only be used after the socket has been set to pause upon notifications and a notification has been received. The only notification currently supported is QSslSocket::sslErrors(). Calling this method if the socket is not paused results in undefined behavior.

我觉得在这种情况下我不应该使用该功能,但是还有其他解决方案吗?我怎么知道套接字是否暂停?为什么当 QTcpSocket 的 内部读取缓冲区不再满时,数据传输不会自动继续?

编辑 1:

我已经下载了 Qt(5.10.0) 源代码和 pdb 来调试这种情况,我可以看到 QAbstractSocket::readData() 内部函数有一行“d->socketEngine->setReadNotificationEnabled(true)" 重新启用数据传输,但是 QAbstractSocket::readData() 仅在 [=23= 时被调用]QTcpSocket 内部读取缓冲区为空(qiodevice.cpp;QIODevicePrivate::read();第 1176 行)并且在我的情况下它永远不会为空,因为我只有在它有足够的数据时才读取它完整的数据包。

QAbstractSocket::readData() 不应该在读取缓冲区不再满时调用,而不是在它完全为空时调用?或者我做错了什么?

找到解决方法!

在 Qt5.10 源代码中,我可以清楚地看到 QTcpSpcket 内部读取通知被禁用(qabstractsocket.cpp;bool QAbstractSocketPrivate::canReadNotification();第 697 行)当读取缓冲区已满并启用读取通知时,您需要读取所有缓冲区以使其为空或使用 QAbstractSocket::setReadBufferSize(newSize) 当 newSize 不为 0 时内部启用读取通知(无限制)且不等于 oldSize(qabstractsocket.cpp;void QAbstractSocket::setReadBufferSize(qint64 大小);第 2824 行)。 这是一个简短的功能:

QTcpSocket socket;
qint64 readBufferSize; // Current max read buffer size.
bool flag = false; // flag for changing max read buffer size.
bool isReadBufferLimitReached = false;

void App::CheckReadBufferLimitReached()
{
    if (readBufferSize <= socket.bytesAvailable())
        isReadBufferLimitReached = true;
    else if (isReadBufferLimitReached)
    {
        if (flag)
        {
            readBufferSize++;
            flag = !flag;
        }
        else
        {
            readBufferSize--;
            flag = !flag;
        }
        socket.setReadBufferSize(readBufferSize);
        isReadBufferLimitReached = false;
    }
}

在以设定的时间间隔从QTcpSocket读取数据的函数中,在读取数据之前,我调用了这个函数,它检查读取缓冲区是否已满并设置isReadBufferLimitReached 如果为真。然后我从 QTcpSocket 读取所需的数据量,最后我再次调用该函数,如果之前缓冲区已满,则调用 QAbstractSocket::setReadBufferSize(size) 来设置新缓冲区大小并启用内部读取通知。将读取缓冲区大小更改 +/-1 应该是安全的,因为您至少从套接字读取了 1 个字节。