read and write to qtcpsocket using qdatastream



  • There are various methods of reading and writing from a QTcpSocket using a QDatastream as seen here

    The difference is, I will be sending more than "one packet" or blocks.

    A basic implementation on the server (sending) side and client (recieving) is seen below - only the actual sending and receiving snippets are shown

    More Info, What I tried:

    When writing to a QTcpSocket, I attempted to use the QTcpSocket::canReadLine() however this fails straightup after the QTcpSocket::waitForReadReady() signal fires.

    I then tried QDataStream::atEnd() in a while loop which causes a system crash :(

    The code below shows my latest attempt of going through the QDataStream docs, and utilzing the commitTransaction where it states

    If no full packet is received, this code restores the stream to the initial position, after which you need to wait for more data to arrive.

    Under the heading Using Read Transactions. But ofcourse, this just reads one block that is sent, i.e the first block.

    Question:

    When writing to a QTcpSocket multiple times, and flushing the socket each time to send that data, how can I read this from a QTcpSocket as it is send, keep the original "send structure"?

    The example below only reads the first block and ends. I would like to read the block containing "Response 2" and "Response 3".

    Code Implementations:

    //server.h

    //...
    QTcpSocket *clientSocket = nullptr;
    QDataStream in;
    //...
    

    //server.cpp

    //...
    in.setDevice(clientSocket);
    in.setVersion(QDataStream::Qt_4_0);
    
    in.startTransaction();
    
    QString nextFortune;
    in >> nextFortune;
    
    if (in.commitTransaction())
        ui->lblOut->setText(nextFortune);
    
    if (clientSocket != nullptr) {
        if (!clientSocket->isValid()) {
            qDebug() << "tcp socket invalid";
            return;
        }
        if (!clientSocket->isOpen()) {
            qDebug() << "tcp socket not open";
            return;
        }
    
        QByteArray block;
        QDataStream out(&block, QIODevice::WriteOnly);
        out.setVersion(QDataStream::Qt_4_0);
    
        out << QString(QString("Response:") + nextFortune);
        if (!clientSocket->write(block)){
            QMessageBox::information(this, tr("Server"),tr("Could not send message"));
        }
        clientSocket->flush();
    //        block.clear();
    
        out << QString("Response number 2");
        if (!clientSocket->write(block)){
            QMessageBox::information(this, tr("Server"),tr("Could not send message"));
        }
        clientSocket->flush();
    //        block.clear();
    
        out << QString("Response number 3 here, and this is the end!");
        if (!clientSocket->write(block)){
            QMessageBox::information(this, tr("Server"),tr("Could not send message"));
        }
        clientSocket->flush();
        clientSocket->disconnectFromHost();
    
    }
    //...
    

    And the client side

    //client.h

    //...
    QTcpSocket *tcp_con = nullptr;
    QDataStream in;
    //...
    

    //client.cpp

    //...
    if(!tcp_con->waitForReadyRead()){
        qDebug(log_lib_netman_err) << "tcp con timeout for reading";
        tcp_con->disconnectFromHost();
        return ReturnObject(ReturnCode::SocketError, QString());
    }
    
    in.setDevice(tcp_con);
    in.setVersion(QDataStream::Qt_4_0);
    
    in.startTransaction();
    
    QList<QString> data_rcv = QList<QString>();
    QString s;
    
    //    while (tcp_con->canReadLine()) {
    //        in >> s;
    //        data_rcv.push_back(s);
    //    }
    //    while (!in.read) {
    in >> s;
    data_rcv.push_back(s);
    //    }
    
    
    while (!in.commitTransaction()){
        qDebug(log_lib_netman_info) << "waiting for more data";
        in >> s;
        data_rcv.push_back(s);
        //        qDebug(log_lib_netman_err) << "Unable to send data to server";
        //        tcp_con->disconnectFromHost();
        //        return ReturnObject(ReturnCode::FailedReceiving, QString());
    }
    
    //    if (s.isEmpty()) {
    //        qDebug(log_lib_netman_err) << "Empty response recieved";
    //        tcp_con->disconnectFromHost();
    //        return ReturnObject(ReturnCode::NoDataRecieved, QString());
    //    }
    
    tcp_con->disconnectFromHost();
    return ReturnObject(ReturnCode::ReceivedSuccess, data_rcv);
    

    Help would be greatly appreciated!


  • Moderators

    @CybeX said in read and write to qtcpsocket using qdatastream:

    Question:
    When writing to a QTcpSocket multiple times, and flushing the socket each time to send that data, how can I read this from a QTcpSocket as it is send, keep the original "send structure"?
    The example below only reads the first block and ends. I would like to read the block containing "Response 2" and "Response 3".

    A simple No.

    In extreme you can rely only that your sending structure is maintained throughout the process is when you are considering one byte as structure. The readyRead signal may be fired any time when receiving data. It depends on how busy the event loop is, the speed of transfer and the speed of computer.

    A not very reliable option would be to wait long enough before reading the data. However, waitForReadRead does support only waiting for a certain, but it is passed as soon as bytes are received. You need to think about handling this yourself. Typically one is sending the size of the subsequent structure first. So you know at least how many bytes have to be received.



  • I've posted an answer how to know if you have read everything here: https://stackoverflow.com/a/46162082/969016


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.