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

时间:2018-03-26 13:57:26

标签: c++ qt qtcpsocket qt5.10

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

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

  

继续在套接字上传输数据。只应使用此方法   套接字设置为暂停通知和a后   已收到通知。目前唯一的通知   支持的是QSslSocket :: sslErrors()。如果调用此方法   套接字未暂停导致未定义的行为。

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

编辑1:

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

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

1 个答案:

答案 0 :(得分:0)

找到了解决方法!

在Qt5.10源代码中,当读取缓冲区已满并启用时,我可以清楚地看到 QTcpSpcket 内部读取通知被禁用(qabstractsocket.cpp; bool QAbstractSocketPrivate :: canReadNotification();第697行)读取需要读取所有缓冲区以使其为空的通知或使用 QAbstractSocket :: setReadBufferSize(newSize)在内部启用读取通知当newSize不为0(无限制)且不等于oldSize(qabstractsocket.cpp)时; void QAbstractSocket :: setReadBufferSize(qint64 size);第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个字节。