QTcpSocket how to receive different type of serialized objects in sequential ?



  • current problem

    I write a class inherit form qtcpserver .this server will handle many clients , I override the method incommingConnection . if there comes new client , i will start a thread to handle it .

    but each client connect to server will send a config object first , so the server will receive the serialized config object first ,then return some info to client .then client will sendserialized realtime infor object to server periodically . in every thread has a pointer to qtcpsocket ,connect it toreadyreadfunction

    My question is how should i do in readyreadfunction that i can get the qdatastream into property serialized object ?because first receive is config object, then comes the periodically realtime info object.


  • Moderators

    Think of a QTcpClient as of a binary file. Whatever you have to write to a binary file in order to read it properly later on is also required here.

    There are many ways to do this. Most popular is to send before a short record or sequence of bytes to identify what comes next.



  • thanks for your answer ,but i don't get your point . As you say send some sequence bytes to identify what come next ,so what is the property way to do in that function ?

    //connect function 
    connect(tcpSocket, &QIODevice::readyRead, this, &FortuneThread::getInfo);
    
    //get info
    void FortuneThread::getInfo()
    {
    		in.startTransaction();
                    
                     //what should i do here to judge what serialized object come in ?
    		//if some sequential bytes to identify ,like string 
                    //just like the flowing code ?
                    in>>identifyString ;
                    switch(identifyString )
                            {
                                   //some handle 
                              }
                     //but how to handle if comes in is serialized object ?
                    
    		if (!in.commitTransaction())
    			return;		
    
    }
    


  • The more involved way is to treat the server as a state machine (http://doc.qt.io/qt-5/statemachine-api.html) so it changes state after it receives the config and is ready to recieve other data.

    The more dirty way is to define an enum with the type of transmission and append it at the beginning of the message.

    For example:

    enum TransmissionType :qint32 {
    sendingConfig = 8 // (a random number, I like 8, leave 0 for errors or special cases)
    , sendingRealtimeInfo
    }
    

    then every client before sending the actual data sends out one of those enum values (as a 32bit integer) so that when the server receives some data, it first reads this number to decide what kind of data it should read



  • @VRonin
    your answer is really helpful . but i still have not fully got your point .you say send the enum values , it's include realtimeInfo object in it ?

    if send enum value first ,then comes the serialized object ,so how to determine its enum or object ?

    void FortuneThread::getInfo()
    {
    		in.startTransaction();
                    
                   //do like this ?
                    in>>enmu_value ;
                   switch (enmu_value) 
                      {
                             in>>object;
                      }
                   
    		if (!in.commitTransaction())
    			return;		
    }
    


  • Untested code!!!

    [I do not use transaction but the old data size header, you should use transactions]

    sender (assume client)

    void Client::sendConfig(const ConfigClass& val)
    {
        QByteArray block;
        QDataStream out(&block, QIODevice::WriteOnly);
        out
            << static_cast<qint32>(0) //you can skip this if you use transactions
            << static_cast<qint32>(TransmissionType::sendingConfig)
            << val
            ;
        out.device()->seek(0); //you can skip this if you use transactions
        out << static_cast<qint32>(block.size() - sizeof(qint32)); //you can skip this if you use transactions
        m_tcpSocket->write(block);
    }
    
    void Client::sendRealtimeInfo(const RealtimeInfo& val)
    {
        QByteArray block;
        QDataStream out(&block, QIODevice::WriteOnly);
        out
            << static_cast<qint32>(0) //you can skip this if you use transactions
            << static_cast<qint32>(TransmissionType::sendingRealtimeInfo)
            << val
            ;
        out.device()->seek(0); //you can skip this if you use transactions 
        out << static_cast<qint32>(block.size() - sizeof(qint32)); //you can skip this if you use transactions
        m_tcpSocket->write(block);
    }
    

    receiver (assume server)

    // qint32 m_nextBlockSize;
    // connect(m_tcpSocket, &QTcpSocket::readyRead, this, &Server::ReadTransmission);
    void Server::ReadTransmission()
    {
        QDataStream incom(m_tcpSocket);
        qint32 RequestType;
        for (;;) {
            //from here
            if (m_nextBlockSize == 0) {
                if (m_tcpSocket->bytesAvailable() < sizeof(qint32))
                    break;
                incom >> m_nextBlockSize;
            }
            if (m_tcpSocket->bytesAvailable() < m_nextBlockSize)
                break;
            //to here can be replaced using transactions
            incom >> RequestType;
            switch (RequestType) {
            case TransmissionType::sendingConfig:{
                ConfigClass val;
                incom >> val;
                // do something with the config
            }
                                                 break;
            case TransmissionType::sendingRealtimeInfo:{
                RealtimeInfo val;
                incom >> val;
                // do something with the realtime info
            }
                                                       break;
            }
            m_nextBlockSize = 0;
        }
    }
    


  • @VRonin
    thanks very much , now i have now your idea .Use a qint32 value as enum value ,put it in qdatastream first ,then put needed data in the same qdatastream .

    i almost forget that one stream can read in more than one type value .thank your very much again .


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.