QTcpSocket
用于接收数据时,使用的信号是readyRead()
,表示有新数据可用。但是,当您在相应的插槽实现中读取数据时,不会readyRead()
发出额外的数据。这可能是有道理的,因为您已经在函数中,您正在读取所有可用数据。
问题描述
但是,假设此插槽的以下实现:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
如果一些数据在调用之后readAll()
但在离开插槽之前到达怎么办?如果这是其他应用程序发送的最后一个数据包(或者至少是一段时间内的最后一个)怎么办?不会发出额外的信号,因此您必须确保自己读取所有数据。
最小化问题的一种方法(但不能完全避免)
当然我们可以这样修改slot:
void readSocketData()
{
while(socket->bytesAvailable())
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
但是,我们还没有解决问题。数据仍然有可能在socket->bytesAvailable()
-check 之后到达(甚至将/另一个检查放在函数的绝对末尾也不能解决这个问题)。
确保能够重现问题
由于这个问题当然很少发生,所以我坚持第一个实现插槽,我什至会添加一个人为的超时,以确保问题发生:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
// wait, to make sure that some data arrived
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
}
然后我让另一个应用程序发送 100,000 字节的数据。这就是发生的事情:
新连接!
32768(或 16K 或 48K)
消息的第一部分被读取,但结尾不再被读取,因为readyRead()
不会再被调用。
我的问题是:确定这个问题永远不会发生的最好方法是什么?
可能的解决方案
我想出的一个解决方案是在最后再次调用同一个插槽,并在插槽的开头检查是否还有更多数据要读取:
void readSocketData(bool selfCall) // default parameter selfCall=false in .h
{
if (selfCall && !socket->bytesAvailable())
return;
datacounter += socket->readAll().length();
qDebug() << datacounter;
QEventLoop loop;
QTimer::singleShot(1000, &loop, SLOT(quit()));
loop.exec();
QTimer::singleShot(0, this, SLOT(readSocketDataSelfCall()));
}
void readSocketDataSelfCall()
{
readSocketData(true);
}
由于我不直接调用插槽,而是使用QTimer::singleShot()
,因此我假设QTcpSocket
无法知道我正在再次调用插槽,因此readyRead()
不会再发生未发出的问题。
我包含该参数的原因是不允许bool selfCall
被调用的插槽更快退出,否则可能会再次出现相同的问题,即数据恰好在错误的时刻到达并且没有发出。QTcpSocket
readyRead()
这真的是解决我的问题的最佳解决方案吗?这个问题的存在是 Qt 中的设计错误还是我遗漏了什么?