Сигнал QTcpSocket readyRead() испускается дважды

У меня QTcpServer. Я хочу отправлять большие данные со стороны клиента и как поймать сигнал, когда все данные получены на сервере? «пока (сокет-> доступные байты)» не работает.

Например:

когда размер qbytearray равен 9000, который отправляется с клиента, на сервере это 4000 или 5000...

Пример второй:

В этом случае СИГНАЛ readyRead() испускается 8 раз.

void Client::SendMessage(std::vector<QString>)
{
    MyClass _Send;
            _Send.Age = 22;
            _Send.School = 14;
            _Send.Name = "Taz";

    QVector<MyClass2> vv;

    for (int i = 0; i < 15000; i++) {
        vv.push_back(MyClass2(24, "leri"));
        vv.push_back(MyClass2(22, "tazo"));
    }

    _Send.vctr = vv;

    QByteArray bytes;
    QDataStream stream(&bytes, QIODevice::WriteOnly);

    int FunctionUID = 331;
    int ij, ik = ij = 169;
    MyClass2 faf(-31, "15");

    stream << FunctionUID << _Send << faf << ij << ik;

    socket->write(bytes);
}



void Server::ImReady()
{
    QByteArray buf;

    buf = socket->readAll();

    QDataStream stream(&buf, QIODevice::ReadOnly);

    int FunctionUID, ij, ik;
    MyClass vv;
    MyClass2 vv1;

    stream >> FunctionUID >> vv >> vv1 >> ij >> ik;

    qDebug() << vv.vctr.size() << "faf";
}

void Server::incomingConnection(qintptr val)
{
    qDebug() << "Client Connected" << val;

    socket = new QTcpSocket;
    socket->setSocketDescriptor(val);

    if (!socket) {
        return;
    }

    connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
    connect(socket, SIGNAL(readyRead()), this, SLOT(ImReady()));
}

person Tazo leladze    schedule 12.10.2017    source источник
comment
Данные не всегда отправляются в виде одного пакета. Если он достаточно велик, его можно отправить в виде фрагментов данных. Вероятно, поэтому вы получаете несколько сигналов readyRead.   -  person vahancho    schedule 12.10.2017
comment
Если вы используете Qt 5.7 или новее, вы можете воспользоваться преимуществами читать транзакции в QDataStream. Взгляните на пример клиента fortune, чтобы увидеть, как это может быть реализован.   -  person thuga    schedule 12.10.2017


Ответы (1)


TCP не отправляет сообщения, это поток данных. Это означает, что вы не можете просто прочитать все имеющиеся данные и рассмотреть только это сообщение. Вместо этого обычно отправляется заголовок, содержащий размер сообщения, и тогда получатель знает, сколько нужно прочитать, чтобы получить все сообщение (и только это, а не читать в следующем).

Это означает, что ваш слот будет делать что-то вроде этого

void Server::ImReady()
{
   uint32 size;
   socket->read(&size, 4);
   uint32 readTotal = 0;
   do {
     readTotal += socket->read(buffer, size-readTotal);
   } while (readTotal < size);
}

Вы можете поставить строку, например

if (socket->bytesAvailable() == 0)
  return;

в начале слота, и тогда вам будет все равно, если сигнал будет испускаться более одного раза за сообщение.

Обратите внимание, что приведенный выше код требует дополнительной обработки ошибок, например. вы должны убедиться, что первый read читает все 4 байта и всегда обрабатывает возвращаемое значение -1.

person Karsten Koop    schedule 12.10.2017
comment
я думаю, это очень полезно. но у меня проблема с суммой, теперь у меня 'uint32' и нет соответствующего вызова socket->read(QByteArray) - person Tazo leladze; 12.10.2017
comment
Существуют перегрузки для QTcpSocket::read, одна из которых использует массив байтов и возвращает количество прочитанных байтов, а другая возвращает QByteArray. Вы должны адаптировать код в зависимости от того, какой из них вы используете. Код в ответе будет использовать массив байтов, buffer будет простым char[] - person Karsten Koop; 12.10.2017