Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Erratic writes to QTcpSocket via QDataStream
QtWS25 Last Chance

Erratic writes to QTcpSocket via QDataStream

Scheduled Pinned Locked Moved Solved General and Desktop
qtcpsocket
11 Posts 2 Posters 968 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V vikramg
    14 Dec 2023, 02:55

    In a simple TCP client/server application I have at the transmit end:

    void MainWindow::sendMessage(QString m)
    {
        QDataStream sockStream(&socket);
        sockStream.setVersion(QDataStream::Qt_5_9);
    
        QByteArray byteArray = m.toUtf8();
        sockStream << byteArray;
    }
    

    App sends a string on a button press:

    void MainWindow::on_pushButton_sendMessage_clicked()
    {
        QString str = ui->lineEdit_message->text();
        sendMessage(str);
    }
    

    At the receiving end, it is retrieved thus:

    void MainWindow::readSocket()
    {
        QTcpSocket* socket = reinterpret_cast<QTcpSocket*>(sender());
    
        QByteArray buffer;
    
        QDataStream socketStream(socket);
        socketStream.setVersion(QDataStream::Qt_5_9);
    
        socketStream.startTransaction();
        socketStream >> buffer;
    
        if(!socketStream.commitTransaction()) {
            return;
        }
    
       QString msg = QString::fromStdString(buffer.toStdString());
       qDebug() << "Received " <<  msg;
    }
    

    This works 100% of the time as presented above. However, if I try to send two strings on every button press:

    void MainWindow::on_pushButton_sendMessage_clicked()
    {
        QString str = ui->lineEdit_message->text();
        sendMessage("$");
        sendMessage(str);
    }
    

    the connection becomes erratic; only the $ gets sent on one button press, then the next string might go on the next press, or just an empty string might get sent.

    The situation improves if I add socket->flush after each write:

        slotSendMessage("$");
        socket->flush();
        slotSendMessage(str);
        socket->flush();
    

    but this still does not work 100% of the time. What is causing this behavior and how can it be remedied?

    C Offline
    C Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on 14 Dec 2023, 04:51 last edited by
    #2

    @vikramg said in Erratic writes to QTcpSocket via QDataStream:

    What is causing this behavior and how can it be remedied?

    There might be already all data on the first emit of readyRead() but you don't handle this.

    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
    Visit the Qt Academy at https://academy.qt.io/catalog

    V 1 Reply Last reply 14 Dec 2023, 05:06
    0
    • C Christian Ehrlicher
      14 Dec 2023, 04:51

      @vikramg said in Erratic writes to QTcpSocket via QDataStream:

      What is causing this behavior and how can it be remedied?

      There might be already all data on the first emit of readyRead() but you don't handle this.

      V Offline
      V Offline
      vikramg
      wrote on 14 Dec 2023, 05:06 last edited by
      #3

      @Christian-Ehrlicher

      There might be already all data on the first emit of readyRead() but you don't handle this.

      How is it to be handled? Isn't

          socketStream.startTransaction();
          socketStream >> buffer;
      

      sufficient?

      C 1 Reply Last reply 14 Dec 2023, 05:08
      0
      • V vikramg
        14 Dec 2023, 05:06

        @Christian-Ehrlicher

        There might be already all data on the first emit of readyRead() but you don't handle this.

        How is it to be handled? Isn't

            socketStream.startTransaction();
            socketStream >> buffer;
        

        sufficient?

        C Offline
        C Offline
        Christian Ehrlicher
        Lifetime Qt Champion
        wrote on 14 Dec 2023, 05:08 last edited by
        #4

        When you expect two byte arrays you should try to read two. As I said readyRead may be fired only once when you send those two strings.

        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
        Visit the Qt Academy at https://academy.qt.io/catalog

        V 1 Reply Last reply 14 Dec 2023, 05:57
        1
        • C Christian Ehrlicher
          14 Dec 2023, 05:08

          When you expect two byte arrays you should try to read two. As I said readyRead may be fired only once when you send those two strings.

          V Offline
          V Offline
          vikramg
          wrote on 14 Dec 2023, 05:57 last edited by
          #5

          @Christian-Ehrlicher Thank you, the following worked:

              socketStream.startTransaction();
              socketStream >> buffer;
              socketStream >> buffer2;
          

          Is there a way to make this generic? i.e. "read as many QByteArrays as are available in this DataStream"? Or "keep trying to read till no more"?

          C 1 Reply Last reply 14 Dec 2023, 05:59
          0
          • V vikramg
            14 Dec 2023, 05:57

            @Christian-Ehrlicher Thank you, the following worked:

                socketStream.startTransaction();
                socketStream >> buffer;
                socketStream >> buffer2;
            

            Is there a way to make this generic? i.e. "read as many QByteArrays as are available in this DataStream"? Or "keep trying to read till no more"?

            C Offline
            C Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on 14 Dec 2023, 05:59 last edited by
            #6

            @vikramg said in Erratic writes to QTcpSocket via QDataStream:

            Or "keep trying to read till no more"?

            Use a loop.

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            V 1 Reply Last reply 14 Dec 2023, 06:18
            1
            • C Christian Ehrlicher
              14 Dec 2023, 05:59

              @vikramg said in Erratic writes to QTcpSocket via QDataStream:

              Or "keep trying to read till no more"?

              Use a loop.

              V Offline
              V Offline
              vikramg
              wrote on 14 Dec 2023, 06:18 last edited by
              #7

              Haha, thank you @Christian-Ehrlicher for the minimalist help :)

              For the benefit of others like myself looking for a cookbook solution: the aptly-named atEnd() member of QDataStream serves as the loop terminating condition, so the following works:

                  do {
                      socketStream >> buffer;
                      qDebug() << "Received " << QString::fromStdString(buffer.toStdString());
                  } while (!socketStream.atEnd());
              
              C 1 Reply Last reply 14 Dec 2023, 06:28
              0
              • V vikramg has marked this topic as solved on 14 Dec 2023, 06:18
              • V vikramg
                14 Dec 2023, 06:18

                Haha, thank you @Christian-Ehrlicher for the minimalist help :)

                For the benefit of others like myself looking for a cookbook solution: the aptly-named atEnd() member of QDataStream serves as the loop terminating condition, so the following works:

                    do {
                        socketStream >> buffer;
                        qDebug() << "Received " << QString::fromStdString(buffer.toStdString());
                    } while (!socketStream.atEnd());
                
                C Offline
                C Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on 14 Dec 2023, 06:28 last edited by Christian Ehrlicher
                #8

                Your solution is wrong as it reverts the complete transaction. Why not a simple loop

                QByteArray buffer;
                QDataStream socketStream(socket);
                socketStream.setVersion(QDataStream::Qt_5_9);
                do {
                    socketStream.startTransaction();
                    socketStream >> buffer;
                } while(socketStream.commitTransaction());
                

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                V 1 Reply Last reply 14 Dec 2023, 06:57
                1
                • C Christian Ehrlicher
                  14 Dec 2023, 06:28

                  Your solution is wrong as it reverts the complete transaction. Why not a simple loop

                  QByteArray buffer;
                  QDataStream socketStream(socket);
                  socketStream.setVersion(QDataStream::Qt_5_9);
                  do {
                      socketStream.startTransaction();
                      socketStream >> buffer;
                  } while(socketStream.commitTransaction());
                  
                  V Offline
                  V Offline
                  vikramg
                  wrote on 14 Dec 2023, 06:57 last edited by
                  #9

                  Ah, then this is what I was looking for; I have minimal working knowledge of QDataStream, and don't really understand what "transactions" are. I was hoping to keep it a black box for now, but I guess I need to dive into it.

                  Can you explain what you mean by "reverts the complete transaction"? I tried your code, but it results in one additional empty string. e.g. if I send ^, hello, and $, it prints those three and an additional empty string. The version I proposed did receive three strings correctly.

                  C 1 Reply Last reply 14 Dec 2023, 07:01
                  0
                  • V vikramg
                    14 Dec 2023, 06:57

                    Ah, then this is what I was looking for; I have minimal working knowledge of QDataStream, and don't really understand what "transactions" are. I was hoping to keep it a black box for now, but I guess I need to dive into it.

                    Can you explain what you mean by "reverts the complete transaction"? I tried your code, but it results in one additional empty string. e.g. if I send ^, hello, and $, it prints those three and an additional empty string. The version I proposed did receive three strings correctly.

                    C Offline
                    C Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on 14 Dec 2023, 07:01 last edited by Christian Ehrlicher
                    #10

                    When e.g. one of your strings is not yet received completely, the transaction reverts the state of the QIODevice back to the state before the transaction started. So in the next readyRead() the string will be read from the beginning / is not truncated.

                    Yes, you get an empty string with my example because you should only output a string when the transaction was successful. My loop is therefore a little bit to easy if you really want to do something with the strings.

                    QByteArray buffer;
                    QDataStream socketStream(socket);
                    socketStream.setVersion(QDataStream::Qt_5_9);
                    do {
                        socketStream.startTransaction();
                        socketStream >> buffer;
                        if (socketStream.commitTransaction()) {
                           doSomething(QString::fromUtf8(buffer));
                        } else {
                          break;
                        }
                    } while (true);
                    

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    V 1 Reply Last reply 14 Dec 2023, 07:23
                    2
                    • C Christian Ehrlicher
                      14 Dec 2023, 07:01

                      When e.g. one of your strings is not yet received completely, the transaction reverts the state of the QIODevice back to the state before the transaction started. So in the next readyRead() the string will be read from the beginning / is not truncated.

                      Yes, you get an empty string with my example because you should only output a string when the transaction was successful. My loop is therefore a little bit to easy if you really want to do something with the strings.

                      QByteArray buffer;
                      QDataStream socketStream(socket);
                      socketStream.setVersion(QDataStream::Qt_5_9);
                      do {
                          socketStream.startTransaction();
                          socketStream >> buffer;
                          if (socketStream.commitTransaction()) {
                             doSomething(QString::fromUtf8(buffer));
                          } else {
                            break;
                          }
                      } while (true);
                      
                      V Offline
                      V Offline
                      vikramg
                      wrote on 14 Dec 2023, 07:23 last edited by
                      #11

                      @Christian-Ehrlicher yes, this works perfectly.

                      I am beginning to understand transactions as well, although it warrants further study. Thank you for the pointers, I appreciate it!

                      1 Reply Last reply
                      0

                      11/11

                      14 Dec 2023, 07:23

                      • Login

                      • Login or register to search.
                      11 out of 11
                      • First post
                        11/11
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved