Qt QTcpServerWork Good But In Linux i have problem....



  • Hello, i don't misunderstand why this code not working on Linux.

    1. QTcpServer
    class CTcpServer : public QTcpServer
    {       
        //...some code
        private slots:
        void incomingConnection(qintptr socketDescriptor);
     }
    
    void CTcpServer::incomingConnection(qintptr socketDescriptor)
    {     CSessionManager::Instance()>AddTcpSocketConnection(socketDescriptor);
    }
    
    1. Class for handling session(SessionManager).
      This class wait few sockets and his next step create thread where this few sockets join for group working..
    void CSessionManager::AddTcpSocketConnection(qintptr socketDesctiptor)
    {
       CTcpSocket * lpSocket = new CTcpSocket();
        if(lpSocket->setSocketDescriptor(socketDesctiptor))
        {
            connect(lpSocket, SIGNAL(BindReady(CTcpSocket*)), this, SLOT(BindReady(CTcpSocket*)));
            lpSocket->InitSignals();
        }
        else
            lpSocket->deleteLater();
    }
    
    1. QTcpSocket - this simple logic for check data when first data transfer on server, if transferred data is ok, this socket move to vector.
    class CTcpSocket : public QTcpSocket
            {
    
                Q_OBJECT
                public:
    
                explicit CTcpSocket(QObject * parent = 0);
    
                ~CTcpSocket();
                bool IsMasterBind();
                bool IsSlaveBind();
                void InitSignals();
                void ReleaseSignals();
               //some code
    
                private slots:
                void TcpDataReadyRead();
    
                signals:
                void BindReady(CTcpSocket *);
    }
    
    void  CTcpSocket::InitSignals()
    {
        connect(this,
                SIGNAL(readyRead()),
                this,
                SLOT(TcpDataReadyRead()));
    
        connect(this,
                SIGNAL(disconnected()),
                this, SLOT(deleteLater()));
    
        m_bMasterBind = false;
        m_bSlaveBind  = false;
    
    }
    
    void CTcpSocket::ReleaseSignals()
    {
        disconnect(this,
                   SIGNAL(readyRead()),
                   this,
                   SLOT(TcpDataReadyRead()));
    
        disconnect(this,
                   SIGNAL(disconnected()),
                   this,
                   SLOT(deleteLater()));
    }
    void CTcpSocket::TcpDataReadyRead()
    {
         m_buffer += this->readAll();
         if(m_buffer == "Master") //For example
               m_bMasterBind = true;
        else if(m_buffer == "Slave") //For example
              m_bSlaveBind = true;
      //some code for check  data if is ok 
       emit BindReady(this);
    }
    

    so if BindReady return to CSessionManager..

    void CSessionManager::BindReady(CTcpSocket * ptr)
    {
        qDebug() << "Bind Signal Ready!";
        if(ptr->IsMasterBind())
        {
               ptr->ReleaseSignals(); //Yes new data must going in thead...
               m_sockdesklist.push_back(ptr);
        }
        else if(ptr->IsSlaveBind())
        {
           QVector<CTcpSocket*>::iterator it;
            for(it = m_sockdesklist.begin();
                it != m_sockdesklist.end();
                it++)
            {
                rdt::CTcpSocket * lpMaster = *it;
                if(lpMaster->IsMasterBind())
                {
                      ptr->ReleaseSignals();
                     //Yes new data going in thead...
                     //Create Thread !!
    CSessionThread * lpThread = new  CSessionThread(lpMaster->socketDescriptor(), ptr->socketDescriptor(), "some arg",  this);
     connect(lpThread, SIGNAL(finished()), lpThread, SLOT(deleteLater()));
    //Thread Created 
     lpThread->start();
      }           
     }
    }
    
    1. CSessionThread for two sockets....
    class CSessionThread : public QThread
    {
                Q_OBJECT
                public:
                explicit CSessionThread(qintptr sockSrc,
                                        qintptr sockDst,
                                        const QString sessionId,
                                        QObject *parent = 0);
       protected:
                void run() override;
      public slots:
                void SrcReadyRead();
                void DstReadyRead();
    
                private:
                QTcpSocket *socketSrc;
                QTcpSocket *socketDst;
                qintptr socketDescriptorSrc;
                qintptr socketDescriptorDst;
    }
    
    CSessionThread::CSessionThread(qintptr sockSrc,
                                        qintptr sockDst,
                                        const QString sessionId,
                                        QObject *parent) :  QThread(parent)
    {
        this->socketDescriptorSrc = sockSrc;
        this->socketDescriptorDst = sockDst;
        this->m_sessionId = sessionId;
    
        if(this->socketDescriptorDst == -1)
            qDebug() << "Dst socket desk error = -1";
    
        if(this->socketDescriptorSrc == -1)
            qDebug() << "Src socket desk error = -1";
    
    }
    
    void CSessionThread::run()
    {
           qDebug() << " Thread started";
          socketSrc = new QTcpSocket();
          socketDst = new QTcpSocket();
          socketSrc->setSocketDescriptor(this->socketDescriptorSrc);
          socketDst->setSocketDescriptor(this->socketDescriptorDst);
           if(socketSrc->isValid()
              && socketDst->isValid())
           {
    connect(socketSrc, SIGNAL(readyRead()), this, 
    SLOT(SrcReadyRead()), Qt::DirectConnection);
    connect(socketDst, SIGNAL(readyRead()), this, 
    SLOT(DstReadyRead()), Qt::DirectConnection);
    socketSrc->readAll();  
    socketDst->readAll(); 
    exec(); 
            socketSrc->abort();
             socketSrc->close();
    
           socketDst->abort();
           socketDst->close();
         }
           socketSrc->deleteLater();
           socketDst->deleteLater();
    }
    
    void CSessionThread::SrcReadyRead()
    {
       THIS CODE NOT WORK CORRECTLY IN LINUX, BUT IN WINDOWS IS OK
        socketDst->write(socketSrc->readAll());
    }
    
    void CSessionThread::DstReadyRead()
    {
        THIS CODE NOT WORK CORRECTLY IN LINUX, BUT IN WINDOWS IS OK
        socketSrc->write(socketDst->readAll());
    }
    

    I Can' understand why this code SrcReadyRead() and DstReadyRead() work is good on Windows but on Linux this work withot errors. In Linux OS This code run some iteration...and still block..

    void rdt::CSessionThread::SrcReadyRead()
    {
    socketDst->write(socketSrc->readAll()); //This Code not receive readyRead In Linux...
    }

    void rdt::CSessionThread::DstReadyRead()
    {
    socketSrc->write(socketDst->readAll()); //This Code not receive readyRead In Linux...
    }

    In Linux, this code is executed several times,
    then it will be blocked, SrcReadyRead and DstReadyRead will not receive signals.
    If I break the connection,
    I will get an error: qsocketnotifier: Invalid socket 20 and type 'Read', disabling.
    From here two questions why it does not work in Linux,
    and in Windows
    it works fine and whether it is possible to monitor two sockets in one thread,
    I do not want to create a separate thread for each socket.
    My task is to create one thread for two sockets.
    And Forward the data between them when the relevant events occur.


  • Moderators

    @Denis-I.

    In a wild guess I assume that the socket buffering in linux is less favorable with the write readAll combination in *ReadyRead routines. Probably you have even high throughput on those tcp sockets. However also low throughput there might be situations where the readyRead will be missed. All dependends on the actual sockjet handling in the OS. I would not even bother to dig deeper.
    Personally I think the combination of write with readAll you do in your code is dangerous and I would avoid in all non-file operations. My suggestion is a small while loop using bytesAvailable and reading chunks.

    More along those lines

    while ( socketDst->bytesAvailable() ) 
    {
          char line[1024];
          qint64 avail = socketDst->bytesAvailable(); 
          qint64 len = avail < 1024 ? avail : 1024;
          socketDst->readLine ( char, len );
    }
    

    Also some precautions to break when too much data is in buffer would be good.

    Note: source above is brain to keyboard. Check it properly.



  • thx koahnig

    while ( socketDst->bytesAvailable() ) 
    {
          char line[1024];
          qint64 avail = socketDst->bytesAvailable(); 
          qint64 len = avail < 1024 ? avail : 1024;
          socketDst->readLine ( char, len );
    }
    

    I replaced with what you wrote, but this is still not a solution. I suspect that on Linux, you can not use two sockets in the same thread, although I may be wrong. Such a feeling that when events occur from one socket, another ceases to work out correctly. I think that it will be necessary to change the architecture of the application, if no solution is found for this problem ...


  • Moderators

    @Denis-I.

    Sorry, the snippet above is missing the sending part, but you probably have figured that part.

    I have used on windows as well as on linux such implementations with no apparent problems. The comms are basically packets of to about 4kB per second.
    However, as already noted above it is wise to take care of stopping the loop in case a large amount of data is in the buffer and needs to read and send again. Therefore, it is important for you to think the data quantities you are expecting.

    Breaking out of the loop after reading a certain amount might be smart for giving other parts the application a chance to get executed. However, you have make sure that you are not forgetting the remainder of the bytes, because readyRead will triggered only when you are not in a connected slot and new data is available.


Log in to reply
 

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