Как сделать так, чтобы сигналы readyRead () от QTcpSocket не могли быть пропущены?
Когда используешьQTcpSocket
чтобы получить данные, сигнал для использованияreadyRead()
, который сигнализирует о наличии новых данных. Однако, когда вы находитесь в соответствующей реализации слота для чтения данных, никаких дополнительныхreadyRead()
будет выпущен Это может иметь смысл, поскольку вы уже находитесь в функции, где вы читаете все доступные данные.
Однако предположим следующую реализацию этого слота:
void readSocketData()
{
datacounter += socket->readAll().length();
qDebug() << datacounter;
}
Что делать, если некоторые данные поступают после вызоваreadAll()
а перед тем как покинуть слот? Что если это был последний пакет данных, отправленный другим приложением (или, по крайней мере, последний за какое-то время)? Никаких дополнительных сигналов не будет, поэтому вы должны убедиться, что прочитали все данные самостоятельно.
Конечно, мы можем изменить слот следующим образом:
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 (или 16К или 48К)
Первая часть сообщения читается, но конец больше не читается, так как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 или я что-то упустил?