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
Forum Updated to NodeBB v4.3 + New Features

Erratic writes to QTcpSocket via QDataStream

Scheduled Pinned Locked Moved Solved General and Desktop
qtcpsocket
11 Posts 2 Posters 1.5k Views 1 Watching
  • 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 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