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. Parsing incomplete json array on QTcpSocket readyRead() , unterminated string
Forum Updated to NodeBB v4.3 + New Features

Parsing incomplete json array on QTcpSocket readyRead() , unterminated string

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 5 Posters 1.1k Views 2 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.
  • mrjjM Offline
    mrjjM Offline
    mrjj
    Lifetime Qt Champion
    wrote on last edited by mrjj
    #3

    @rifky said in [Parsing incomplete json array on QTcpSocket readyRead() , unterminated string]

    QByteArray data = tcpSocketUpdata->readAll();

    Hi
    Have you checked that you get all data?

    Despise the name readAll it might not read all data
    if it comes in more than one packet.

    So my guess is that it comes as multiple reads.

    update: @jsulm also had that feeling :)

    1 Reply Last reply
    5
    • jsulmJ jsulm

      @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

      QByteArray data = tcpSocketUpdata->readAll();

      Where is this executed? My guess is that you call it in a slot connected to readyRead() signal. You have to consider that you can't assume that if readyRead() signal is emitted you get the whole package when calling readAll(). You have to accumulate the data until you got everything and then parse JSON.

      R Offline
      R Offline
      rifky
      wrote on last edited by rifky
      #4

      @jsulm i made custom instance QTcpSocket in order to handle mutiple connection,
      forked original source

      /*------SocksUpdata class-----*/
      SocksUpdata::SocksUpdata(QTcpSocket* socket)
      {
          tcpSocketUpdata = socket;
          connect (tcpSocketUpdata, &QTcpSocket::readyRead, this, &SocksUpdata::slotReadyRead);
          connect (tcpSocketUpdata, &QTcpSocket::disconnected, this, &SocksUpdata::slotDisconnected);
          connect (tcpSocketUpdata, &QTcpSocket::connected, this, &SocksUpdata::slotConnected);
      }
      QByteArray SocksUpdata::getData()
      {
          QByteArray ba = tcpSocketUpdata->readAll();
          return ba;
      }
      
      /*------UpdataServer class-----*/
      void UpdataServer::startListen()
      {
          server = new QTcpServer();
          connect(server, &QTcpServer::newConnection,this, &UpdataServer::slotNewConnection);
          if(!server->listen(QHostAddress::Any, UPDATA_PORT)){
              qDebug()<< "updataServer Could Not be Started port "<<UPDATA_PORT;
              return;
          }else{
              qDebug()<< "updataServer Started port "<<UPDATA_PORT;
          }
      }
      
      void UpdataServer::slotNewConnection()
      {
          QTcpSocket* socket = server->nextPendingConnection();
          SocksUpdata* handle_mutipleSocks = new SocksUpdata(socket);
      
          //setSocketOption
          socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
          socket->setSocketOption(QAbstractSocket::LowDelayOption, 0);
      
      
          qDebug()<<handle_mutipleSocks->getPerrAddress()<<" Connected to updataserver";
      
          //! hs1
          socket->write("Welecome");
      
          //! pairing peeraddress with socketptr
          handle_mutipleSocks->paired_device.insert(socket->peerAddress(),socket);
      
          connect(handle_mutipleSocks, &SocksUpdata::dataReady,this, &UpdataServer::slotReceive);
          connect(handle_mutipleSocks, &SocksUpdata::socketDisconnected,this, &UpdataServer::slotDisconnectSocket);
      }
      
      void UpdataServer::slotReceive(SocksUpdata* socket)
      {
          QByteArray dataReceived = socket->getData();
       qDebug().noquote().noquote()<<" UpdataServer::slotReceive from "<<socket->getPerrAddress()<<" "<<dataReceived;
      }
      
      

      how i can handle it if socket receive complete json with separate payload?

      i got similar issue but, it's different language i used
      https://stackoverflow.com/questions/53937434/parsing-incomplete-json-array

      JonBJ 1 Reply Last reply
      0
      • R rifky

        @jsulm i made custom instance QTcpSocket in order to handle mutiple connection,
        forked original source

        /*------SocksUpdata class-----*/
        SocksUpdata::SocksUpdata(QTcpSocket* socket)
        {
            tcpSocketUpdata = socket;
            connect (tcpSocketUpdata, &QTcpSocket::readyRead, this, &SocksUpdata::slotReadyRead);
            connect (tcpSocketUpdata, &QTcpSocket::disconnected, this, &SocksUpdata::slotDisconnected);
            connect (tcpSocketUpdata, &QTcpSocket::connected, this, &SocksUpdata::slotConnected);
        }
        QByteArray SocksUpdata::getData()
        {
            QByteArray ba = tcpSocketUpdata->readAll();
            return ba;
        }
        
        /*------UpdataServer class-----*/
        void UpdataServer::startListen()
        {
            server = new QTcpServer();
            connect(server, &QTcpServer::newConnection,this, &UpdataServer::slotNewConnection);
            if(!server->listen(QHostAddress::Any, UPDATA_PORT)){
                qDebug()<< "updataServer Could Not be Started port "<<UPDATA_PORT;
                return;
            }else{
                qDebug()<< "updataServer Started port "<<UPDATA_PORT;
            }
        }
        
        void UpdataServer::slotNewConnection()
        {
            QTcpSocket* socket = server->nextPendingConnection();
            SocksUpdata* handle_mutipleSocks = new SocksUpdata(socket);
        
            //setSocketOption
            socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
            socket->setSocketOption(QAbstractSocket::LowDelayOption, 0);
        
        
            qDebug()<<handle_mutipleSocks->getPerrAddress()<<" Connected to updataserver";
        
            //! hs1
            socket->write("Welecome");
        
            //! pairing peeraddress with socketptr
            handle_mutipleSocks->paired_device.insert(socket->peerAddress(),socket);
        
            connect(handle_mutipleSocks, &SocksUpdata::dataReady,this, &UpdataServer::slotReceive);
            connect(handle_mutipleSocks, &SocksUpdata::socketDisconnected,this, &UpdataServer::slotDisconnectSocket);
        }
        
        void UpdataServer::slotReceive(SocksUpdata* socket)
        {
            QByteArray dataReceived = socket->getData();
         qDebug().noquote().noquote()<<" UpdataServer::slotReceive from "<<socket->getPerrAddress()<<" "<<dataReceived;
        }
        
        

        how i can handle it if socket receive complete json with separate payload?

        i got similar issue but, it's different language i used
        https://stackoverflow.com/questions/53937434/parsing-incomplete-json-array

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #5

        @rifky

        QByteArray SocksUpdata::getData()
        {
            QByteArray ba = tcpSocketUpdata->readAll();
            return ba;
        }
        ...
        void UpdataServer::slotReceive(SocksUpdata* socket)
        {
            QByteArray dataReceived = socket->getData();
         qDebug().noquote().noquote()<<" UpdataServer::slotReceive from "<<socket->getPerrAddress()<<" "<<dataReceived;
        }
        

        As both @jsulm & @mrjj have said, this does not guarantee you have received all the data sent from the client. At best it guarantees you have received the first byte of whatever may have been sent!

        @jsulm correctly stated:

        You have to accumulate the data until you got everything and then parse JSON.

        We don't know what protocol you are using between your client & server. It is your job to "invent" one. For example, the client might precede its messages with a byte count, or you might have it send a unique \0 byte to indicate when it has finished sending the document. Then your receiver side must keep going readAll() in its readyRead() socket, buffering up till the protocol indicates it has received the full transfer before trying to parse it.

        You may want to look at QDataStream transactions and the example https://doc.qt.io/qt-5/qtnetwork-fortuneclient-example.html

        1 Reply Last reply
        5
        • R Offline
          R Offline
          rifky
          wrote on last edited by
          #6

          @mrjj said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

          @rifky said in [Parsing incomplete json array on QTcpSocket readyRead() , unterminated string]

          QByteArray data = tcpSocketUpdata->readAll();

          Hi
          Have you checked that you get all data?

          Despise the name readAll it might not read all data
          if it comes in more than one packet.

          So my guess is that it comes as multiple reads.

          update: @jsulm also had that feeling :)

          I haven't done it

          KroMignonK 1 Reply Last reply
          0
          • R rifky

            @mrjj said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

            @rifky said in [Parsing incomplete json array on QTcpSocket readyRead() , unterminated string]

            QByteArray data = tcpSocketUpdata->readAll();

            Hi
            Have you checked that you get all data?

            Despise the name readAll it might not read all data
            if it comes in more than one packet.

            So my guess is that it comes as multiple reads.

            update: @jsulm also had that feeling :)

            I haven't done it

            KroMignonK Offline
            KroMignonK Offline
            KroMignon
            wrote on last edited by
            #7

            @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

            I haven't done it

            As @jsulm and @mrjj have already written, TCP is a stream protocol. When you are sending data from one endpoint to counterpart, all data will arrives but not necessary at the same time. So you can have for QTcpSocket::write() one or more QTcpSocket::dataReady() events.
            You have to store data on receiver side until "message is completely received and then process the full message.

            There are many strategies to achieve this depending on the way you are using the TCP Socket.

            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

            R 1 Reply Last reply
            1
            • KroMignonK KroMignon

              @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

              I haven't done it

              As @jsulm and @mrjj have already written, TCP is a stream protocol. When you are sending data from one endpoint to counterpart, all data will arrives but not necessary at the same time. So you can have for QTcpSocket::write() one or more QTcpSocket::dataReady() events.
              You have to store data on receiver side until "message is completely received and then process the full message.

              There are many strategies to achieve this depending on the way you are using the TCP Socket.

              R Offline
              R Offline
              rifky
              wrote on last edited by
              #8

              @KroMignon said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

              As @jsulm and @mrjj have already written, TCP is a stream protocol. When you are sending data from one endpoint to counterpart, all data will arrives but not necessary at the same time. So you can have for QTcpSocket::write() one or more QTcpSocket::dataReady() events.
              You have to store data on receiver side until "message is completely received and then process the full message.
              There are many strategies to achieve this depending on the way you are using the TCP Socket.

              okay, i'm confused sometimes the issue appears,

              what if
              on readyRead() function :

              readAll response
              parsing to jsonarray
              if error parsing
              assign response to temp_variabel
              finding close bracket json until found
              if found 
              combine with temp_variabel
              then parsing to jsonarray
              

              I thought about it like that shown here

              i have very little knowledge about qt, can you help me with that ?

              thanks

              jsulmJ 1 Reply Last reply
              0
              • R rifky

                @KroMignon said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

                As @jsulm and @mrjj have already written, TCP is a stream protocol. When you are sending data from one endpoint to counterpart, all data will arrives but not necessary at the same time. So you can have for QTcpSocket::write() one or more QTcpSocket::dataReady() events.
                You have to store data on receiver side until "message is completely received and then process the full message.
                There are many strategies to achieve this depending on the way you are using the TCP Socket.

                okay, i'm confused sometimes the issue appears,

                what if
                on readyRead() function :

                readAll response
                parsing to jsonarray
                if error parsing
                assign response to temp_variabel
                finding close bracket json until found
                if found 
                combine with temp_variabel
                then parsing to jsonarray
                

                I thought about it like that shown here

                i have very little knowledge about qt, can you help me with that ?

                thanks

                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #9

                @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

                assign response to temp_variabel

                be careful where you define this variable!
                It has to be a class member and not local variable!

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                1
                • R Offline
                  R Offline
                  rifky
                  wrote on last edited by
                  #10

                  solved , maybe it's not a great solution, but it solves my problem

                  here is my snippet

                  QJsonParseError parseError_2;
                      QJsonParseError parseError_3;
                      QByteArray temp_arr;
                      QJsonDocument document_2 = QJsonDocument::fromJson(byte_json.data(), &parseError_2);
                  
                      if(parseError_2.error != QJsonParseError::NoError){
                          emit setJsonInvalid(this->epoch, byte_json);
                  
                          for (int k=0;k <= this->epoch; k++) {
                              temp_arr.push_back(strJsonInvalid[k]);
                          }
                          //coba parsing
                          QJsonDocument coba_parsing = QJsonDocument::fromJson(temp_arr, &parseError_3);
                  
                          // jika parsing sukses , clear object strJsonInvalid
                          // reset epoch jadi 0
                          if(parseError_3.error == QJsonParseError::NoError){
                              set_JsonValid(coba_parsing);//fire signal for sending valid json
                              strJsonInvalid.clear();
                          }else{
                              //jika masih gagal parsing increment epoch (+1)
                              setEpoch(this->epoch);
                              this->epoch++;
                          }
                      }
                  
                  KroMignonK 1 Reply Last reply
                  0
                  • R rifky

                    solved , maybe it's not a great solution, but it solves my problem

                    here is my snippet

                    QJsonParseError parseError_2;
                        QJsonParseError parseError_3;
                        QByteArray temp_arr;
                        QJsonDocument document_2 = QJsonDocument::fromJson(byte_json.data(), &parseError_2);
                    
                        if(parseError_2.error != QJsonParseError::NoError){
                            emit setJsonInvalid(this->epoch, byte_json);
                    
                            for (int k=0;k <= this->epoch; k++) {
                                temp_arr.push_back(strJsonInvalid[k]);
                            }
                            //coba parsing
                            QJsonDocument coba_parsing = QJsonDocument::fromJson(temp_arr, &parseError_3);
                    
                            // jika parsing sukses , clear object strJsonInvalid
                            // reset epoch jadi 0
                            if(parseError_3.error == QJsonParseError::NoError){
                                set_JsonValid(coba_parsing);//fire signal for sending valid json
                                strJsonInvalid.clear();
                            }else{
                                //jika masih gagal parsing increment epoch (+1)
                                setEpoch(this->epoch);
                                this->epoch++;
                            }
                        }
                    
                    KroMignonK Offline
                    KroMignonK Offline
                    KroMignon
                    wrote on last edited by
                    #11

                    @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

                    solved , maybe it's not a great solution, but it solves my problem

                    As @jsulm has written, the best way is to declare a class member to store temporary value.
                    Then, according to your example, you are search a string with is between [].
                    So one solution would be something like this:

                    class SocksUpdata : public QObject
                    {
                        Q_OBJECT
                    
                    private:
                        QByteArray _buffer;
                    ...
                    };
                    
                    
                    QByteArray SocksUpdata::getData()
                    {
                        _buffer.append(tcpSocketUpdata->readAll());
                    
                        int idx = _buffer.indexOf('[');
                        if(_buffer[0] != '[' && idx > 0)
                        {
                           _buffer.remove(0, idx);
                        }
                        idx = _buffer.indexOf(']');
                        if(_buffer[0] == '['  &&  idx > 0)
                        {
                            QByteArray byte_json = _buffer.left(idx+1);
                            _buffer.remove(0, idx+1);
                            QJsonParseError parseErr;
                            QJsonDocument doc =  QJsonDocument::fromJson(byte_json, &parseErr);
                             if(parseError_2.error != QJsonParseError::NoError)
                             {
                                 emit setJsonInvalid(this->epoch, byte_json);
                             }
                             else
                             {
                                 // do your stuff
                             }
                        }
                    }
                    

                    It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                    R 1 Reply Last reply
                    3
                    • KroMignonK KroMignon

                      @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

                      solved , maybe it's not a great solution, but it solves my problem

                      As @jsulm has written, the best way is to declare a class member to store temporary value.
                      Then, according to your example, you are search a string with is between [].
                      So one solution would be something like this:

                      class SocksUpdata : public QObject
                      {
                          Q_OBJECT
                      
                      private:
                          QByteArray _buffer;
                      ...
                      };
                      
                      
                      QByteArray SocksUpdata::getData()
                      {
                          _buffer.append(tcpSocketUpdata->readAll());
                      
                          int idx = _buffer.indexOf('[');
                          if(_buffer[0] != '[' && idx > 0)
                          {
                             _buffer.remove(0, idx);
                          }
                          idx = _buffer.indexOf(']');
                          if(_buffer[0] == '['  &&  idx > 0)
                          {
                              QByteArray byte_json = _buffer.left(idx+1);
                              _buffer.remove(0, idx+1);
                              QJsonParseError parseErr;
                              QJsonDocument doc =  QJsonDocument::fromJson(byte_json, &parseErr);
                               if(parseError_2.error != QJsonParseError::NoError)
                               {
                                   emit setJsonInvalid(this->epoch, byte_json);
                               }
                               else
                               {
                                   // do your stuff
                               }
                          }
                      }
                      
                      R Offline
                      R Offline
                      rifky
                      wrote on last edited by
                      #12

                      @KroMignon said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

                      @rifky said in Parsing incomplete json array on QTcpSocket readyRead() , unterminated string:

                      solved , maybe it's not a great solution, but it solves my problem

                      As @jsulm has written, the best way is to declare a class member to store temporary value.
                      Then, according to your example, you are search a string with is between [].
                      So one solution would be something like this:

                      class SocksUpdata : public QObject
                      {
                          Q_OBJECT
                      
                      private:
                          QByteArray _buffer;
                      ...
                      };
                      
                      
                      QByteArray SocksUpdata::getData()
                      {
                          _buffer.append(tcpSocketUpdata->readAll());
                      
                          int idx = _buffer.indexOf('[');
                          if(_buffer[0] != '[' && idx > 0)
                          {
                             _buffer.remove(0, idx);
                          }
                          idx = _buffer.indexOf(']');
                          if(_buffer[0] == '['  &&  idx > 0)
                          {
                              QByteArray byte_json = _buffer.left(idx+1);
                              _buffer.remove(0, idx+1);
                              QJsonParseError parseErr;
                              QJsonDocument doc =  QJsonDocument::fromJson(byte_json, &parseErr);
                               if(parseError_2.error != QJsonParseError::NoError)
                               {
                                   emit setJsonInvalid(this->epoch, byte_json);
                               }
                               else
                               {
                                   // do your stuff
                               }
                          }
                      }
                      

                      thx alot sir, it's working .

                      i got little bit confuse using QbyteArray, i'm trying to made my code working with QHash wich can storing QByteArray, thx for help i'm realy appriciate that :)

                      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