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. Qt QTcpServerWork Good But In Linux i have problem....
QtWS25 Last Chance

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

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 2 Posters 844 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.
  • D Offline
    D Offline
    Denis I.
    wrote on last edited by
    #1

    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.

    K 1 Reply Last reply
    0
    • D Denis I.

      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.

      K Offline
      K Offline
      koahnig
      wrote on last edited by
      #2

      @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.

      Vote the answer(s) that helped you to solve your issue(s)

      1 Reply Last reply
      2
      • D Offline
        D Offline
        Denis I.
        wrote on last edited by
        #3

        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 ...

        K 1 Reply Last reply
        0
        • D Denis I.

          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 ...

          K Offline
          K Offline
          koahnig
          wrote on last edited by
          #4

          @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.

          Vote the answer(s) that helped you to solve your issue(s)

          1 Reply Last reply
          1

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved