我有服务器客户端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()而不是它完全为空时?或者我可能做错了什么?
答案 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个字节。