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 Offline
    V Offline
    vikramg
    wrote on 14 Dec 2023, 02:55 last edited by
    #1

    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 1 Reply Last reply 14 Dec 2023, 04:51
    0
    • 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

                        1/11

                        14 Dec 2023, 02:55

                        • Login

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