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. Best way to handle streaming TCP Data

Best way to handle streaming TCP Data

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 2 Posters 695 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.
  • Renegade243R Offline
    Renegade243R Offline
    Renegade243
    wrote on last edited by
    #1

    Hi,

    I am pretty new to QT and C++, but I have good experience in C and Verilog and I have designed a fairly large GUI frontend to receive streamed data over TCP from a C server running remotely. Whilst I can plot it quite nicely thanks to QCustomPlot and the guidance from some other users. I am looking to improve the performance of my streaming system, but I am not sure what structures or paradigms to adopt as there are a lot of possibilities with QT. Ultimately I will need to receive and plot four separate graphs (in realtime) from data provided in a single packet (4x2048 samples = 32768 bytes), but either way I am looking for a refresh rate on all plots of about 5 Hz. The code below is what I have, but I can see that it is running sub-optimally hogging an entire CPU core at 100% and stuttering badly and dropping packets when the computer is under load. The function is attached to a readyRead slot as indicated below:

    connect(&tcpClient, &QIODevice::readyRead, this, &MainWindow::update);
    

    Could anyone suggest or point me in the direction of a better approach to handle streamed data over TCP in QT ?

        double x,y;
        while(tcpClient.bytesAvailable()){
         
            data_in = tcpClient.read(PayloadSize);
            int numSamples = data_in.size() / 4;
            
            const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
            for (int i=0; i<numSamples; ++i){
                colorMapRTI_1->data()->cellToCoord(i, 0, &x, &y);
                colorMapRTI_1->data()->setCell(i, 0, *ptrFloat);
                ptrFloat++;
            }
            ui->rti_1->replot();
            colorMapRTI_1->rescaleDataRange();
        } // end of while
    ```
    

    Best Regards, Ren

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2

      Have a look at ChatClient::onReadyRead of this example. There is also a paragraph that explains what the code does. In your case you will read floats instead of QByteArray

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      4
      • Renegade243R Offline
        Renegade243R Offline
        Renegade243
        wrote on last edited by
        #3

        Hi,

        @VRonin I tried your code but it had issues identifying whether it was a Tcp streaming connection as it is not set up in the same way on my server end as it is yours. Thank you for sharing your code and article it is nicely documented. Either way I solved my issue through a simple if statement to just wait until it has received a payload of the correct size, though I still need to resolve some minor packet dropping issues (which I suspect is due to received PayloadSize varying slightly) anyway here is the code:

        void MainWindow::onReadyRead(){
            while (tcpClient->bytesAvailable()){
                data_in = tcpClient->read(PayloadSize);
                if (data_in.size() == PayloadSize){
                    di = 0; // set the data index to 0
                    const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
                    updategraph1(ptrFloat);
                    updategraph2(ptrFloat);
                } // end of if found the payload
            } // end of while bytes are available
        } // end of ready read
        

        Best Regards, Ren

        VRoninV 1 Reply Last reply
        0
        • Renegade243R Renegade243

          Hi,

          @VRonin I tried your code but it had issues identifying whether it was a Tcp streaming connection as it is not set up in the same way on my server end as it is yours. Thank you for sharing your code and article it is nicely documented. Either way I solved my issue through a simple if statement to just wait until it has received a payload of the correct size, though I still need to resolve some minor packet dropping issues (which I suspect is due to received PayloadSize varying slightly) anyway here is the code:

          void MainWindow::onReadyRead(){
              while (tcpClient->bytesAvailable()){
                  data_in = tcpClient->read(PayloadSize);
                  if (data_in.size() == PayloadSize){
                      di = 0; // set the data index to 0
                      const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
                      updategraph1(ptrFloat);
                      updategraph2(ptrFloat);
                  } // end of if found the payload
              } // end of while bytes are available
          } // end of ready read
          

          Best Regards, Ren

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          @Renegade243 said in Best way to handle streaming TCP Data:

          data_in = tcpClient->read(PayloadSize);

          The "dropping" issue is here. It should be:

          void MainWindow::onReadyRead(){
              while (tcpClient->bytesAvailable()>=PayloadSize){
                  data_in = tcpClient->read(PayloadSize);
                      di = 0; // set the data index to 0
                      const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
                      updategraph1(ptrFloat);
                      updategraph2(ptrFloat);
              } // end of while bytes are available
          } // end of ready read
          

          it had issues identifying whether it was a Tcp streaming connection as it is not set up in the same way on my server end as it is yours.

          since your data is floats it doesn't matter, QDataStream will just use reinterpret_cast + read() internally making it the same as your read method

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          2
          • Renegade243R Offline
            Renegade243R Offline
            Renegade243
            wrote on last edited by
            #5

            @VRonin

            Thanks, sorry I did not see this post immediately. Interestingly I had to re-address the problem when I moved my network setup to another building, the C server is now physically separated from the client by a 70m network cable. This consequently caused my previous if statement to fail as it never received the full packet size (which it did before when they were right next to each other), instead it is received in partial chunks which need to be reconstructed. Here is the code I used to do so and it works quite well, I am experiencing No performance issues and No network problems at the moment, though I haven't tested the absolute limit of this processing topology. I am confident that it won't struggle under higher refresh rates though.

            If you see a way it can be significantly improved feel free to comment, I believe it will serve as a nice piece of code for users exploring reliable packet reception and processing, I can then mark this issue as solved.

            void MainWindow::onReadyRead(){
                while (tcpClient->bytesAvailable()){
                    data_temp = tcpClient->read(PayloadSize); // tries to read full payload
                    data_temp_size = data_temp.size();
                    //cout << "Data Temp Size: " << data_temp_size << endl;
                    //cout << "Data In Size: " << data_in_size << endl;
                    if (data_in_size+data_temp_size < PayloadSize){
                        data_in.append(data_temp); // keep appending data temp to data in
                        data_in_size += data_temp_size;
                    }
                    else{ // more than payload size
                        data_in.append(data_temp.left(PayloadSize - data_in_size));
                        di = 0; // set the data index to 0
                        const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
                        updatePlots(ptrFloat);
                        data_in.clear();
                        data_in.append(data_temp.right(data_temp_size - (PayloadSize - data_in_size)));
                        data_in_size = data_in.size();
                    } // end of if found the payload
                } // end of while bytes are available
            } // end of ready read
            
            
            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