Как сделать так, чтобы сигналы 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 или я что-то упустил?

Ответы на вопрос(6)

Ваш ответ на вопрос