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.
  • vikramgV Offline
    vikramgV Offline
    vikramg
    wrote on 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?

    Christian EhrlicherC 1 Reply Last reply
    0
    • vikramgV vikramg

      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?

      Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 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

      vikramgV 1 Reply Last reply
      0
      • Christian EhrlicherC Christian Ehrlicher

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

        vikramgV Offline
        vikramgV Offline
        vikramg
        wrote on 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?

        Christian EhrlicherC 1 Reply Last reply
        0
        • vikramgV vikramg

          @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?

          Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on 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

          vikramgV 1 Reply Last reply
          1
          • Christian EhrlicherC Christian Ehrlicher

            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.

            vikramgV Offline
            vikramgV Offline
            vikramg
            wrote on 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"?

            Christian EhrlicherC 1 Reply Last reply
            0
            • vikramgV vikramg

              @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"?

              Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on 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

              vikramgV 1 Reply Last reply
              1
              • Christian EhrlicherC Christian Ehrlicher

                @vikramg said in Erratic writes to QTcpSocket via QDataStream:

                Or "keep trying to read till no more"?

                Use a loop.

                vikramgV Offline
                vikramgV Offline
                vikramg
                wrote on 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());
                
                Christian EhrlicherC 1 Reply Last reply
                0
                • vikramgV vikramg has marked this topic as solved on
                • vikramgV vikramg

                  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());
                  
                  Christian EhrlicherC Offline
                  Christian EhrlicherC Offline
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on 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

                  vikramgV 1 Reply Last reply
                  1
                  • Christian EhrlicherC Christian Ehrlicher

                    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());
                    
                    vikramgV Offline
                    vikramgV Offline
                    vikramg
                    wrote on 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.

                    Christian EhrlicherC 1 Reply Last reply
                    0
                    • vikramgV vikramg

                      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.

                      Christian EhrlicherC Offline
                      Christian EhrlicherC Offline
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on 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

                      vikramgV 1 Reply Last reply
                      2
                      • Christian EhrlicherC Christian Ehrlicher

                        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);
                        
                        vikramgV Offline
                        vikramgV Offline
                        vikramg
                        wrote on 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

                        • Login

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