c++qtqtcpsocketqbytearrayqtcpserver

QTcpSocket readyRead() Signal emitted twice


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()));
}

Solution

  • 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.