2

I have QTcpServer. I want to send large data from client side and how to catch signal, when all data is received on server? "while (socket->bytesavailable)" doesn't work.

For example:

when qbytearray size is 9000, which is send from client, on the server it's 4000 or 5000...

Example Two:

In this Case readyRead() SIGNAL Is Emited 8 times.

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()));
}
talamaki
  • 5,324
  • 1
  • 27
  • 40
Tazo leladze
  • 1,430
  • 1
  • 16
  • 27
  • The data isn't always sent as a single packet. If it's large enough, it can be sent as chunks of data. This is, probably, why you get multiple `readyRead` signals. – vahancho Oct 12 '17 at 11:04
  • If you are using Qt 5.7 or newer, you can take advantage of [read transactions](http://doc.qt.io/qt-5/qdatastream.html#using-read-transactions) in `QDataStream`. Take a look at the [fortune client example](http://doc.qt.io/qt-5/qtnetwork-fortuneclient-example.html) to see how it can be implemented. – thuga Oct 12 '17 at 11:25

1 Answers1

3

TCP does not send messages, it is a stream of data. This means you can't just read all data that's there, and consider this one message. Instead one usually sends a header, containing the message size, and then the receiver knows how much to read to get the whole message (and just this one, not read into the next).

This means your slot would do something like this

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

You could put a line like

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

at the beginning of the slot, and then you would not care at all if the signal is emitted more than once per message.

Note that the code above needs additional error handling, e.g. you must make sure the first read reads all 4 bytes, and always handle a return value of -1.

Karsten Koop
  • 2,475
  • 1
  • 18
  • 23
  • i think, this is very helpfull.but i have sum problem, it is now with me 'uint32' and no matching call socket->read(QByteArray) – Tazo leladze Oct 12 '17 at 11:24
  • There are overloads for `QTcpSocket::read`, one using a byte array and returning the number of bytes read, and the other returning a `QByteArray`. You have to adapt the code depending on which one you use. The code in the answer would use the byte array, `buffer` would be a simple `char[]` – Karsten Koop Oct 12 '17 at 12:28