Threaded SSLServer using QSslSocket With bidirectional communication (avoid "QSocketNotifier: Socket notifiers cannot ...")



  • Hi,

    I have written a SSL Server with threaded socket handling, which works fine
    until I have only a one way communication.

    Since I try to add a bidirectional communication, I get the "QSocketNotifier: Socket notifiers cannot ..." message.

    The reason for this I mostly understand, because of the socket was created in other thread and can not be modified by
    other thread.

    But how do I have to create a socket, which can handled in other thread with read and write to connected client ?
    Each thread can give different answers to the connected clients.

    Best regards
    R.


  • Lifetime Qt Champion

    Hi,

    So you are moving your sockets around in different threads ? Can you explain your architecture in more details ?



  • @SGaist
    I have a base window which will handle the SSLServer listen function

      m_SSLServer->setSslProtocol(QSsl::TlsV1_2);
    
        if (!m_SSLServer->listen(QHostAddress::Any,sTCPIPPort.toInt(&ok, 10)))
           ...
    

    Based on the signal "incomingConnection"

       void incomingConnection(qintptr socketDescriptor) override final;
    

    a thread with the actual socketdescriptor will created by

       QThread* SSL_thread = new QThread;
        TCPThread *m_task = new TCPThread(socketDescriptor,&m_SQLDatabase);   // Create thread object for transmission
        m_task->moveToThread(SSL_thread);
    
        connect( SSL_thread, SIGNAL(started()), m_task, SLOT(doWork()) );
        connect( m_task, SIGNAL(WorkFinished()), SSL_thread, SLOT(quit()) );
    
        //automatically delete thread and task object when work is done:
        connect(SSL_thread, SIGNAL(finished()), m_task, SLOT(deleteLater()));	// Setup stuff by closing the thread
        connect(SSL_thread, SIGNAL(finished()), SSL_thread, SLOT(deleteLater()) );
    //    connect(SSL_thread, SIGNAL(TCPThreadError(QString,int)),
    //                        this, SLOT(ShowTCPThreadError(QString,int)));		// Message queue in matter of errors
        SSL_thread->start();
    

    The class will install the following signals and handle the communication over the signals of the class.

    {
        m_socketDescriptor=socketDS;							// Copy the tcp/iP descriptor locally
        m_SQLDatabase = SQLDatabase;                             // get the connection from the main process
        m_StateMachineState=NoConnection;
        m_blockSize = 0;                                        // No byte received
    
        m_sslSocket.setPrivateKey(ApplicationPath+ "../config/" + sPrivatSSLKey);
        m_sslSocket.setLocalCertificate(ApplicationPath+ "../config/" + sLocalSSLCertificate);
        m_sslSocket.setProtocol(QSsl::TlsV1_2);
        m_sslSocket.ignoreSslErrors();
    
        if ( m_sslSocket.setSocketDescriptor(m_socketDescriptor) == false)	// Connect the socket to the
            {
            m_LastErrorMessage=m_sslSocket.errorString() + tr(": reported from TCP thread");
            emit TCPThreadError(m_LastErrorMessage,1);
            }
    
        connect(&m_sslSocket,SIGNAL(disconnected(void)), this,SLOT(disconnected(void)));
        connect(&m_sslSocket,SIGNAL(hostFound(void)), this,SLOT(hostFound(void)));
        connect(&m_sslSocket,SIGNAL(connected(void)), this,SLOT(connected(void)));
        typedef void (QSslSocket::* sslErrorsSignal)(const QList<QSslError> &);
        connect(&m_sslSocket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors),this, &TCPThread::SSLError);
        connect(&m_sslSocket,SIGNAL(readyRead(void)), this,SLOT(readyRead(void)));
        connect(&m_sslSocket,SIGNAL(aboutToClose(void)), this,SLOT(aboutToClose(void)));
        connect(&m_sslSocket,SIGNAL(bytesWritten(qint64)), this,SLOT(bytesWritten(qint64)));
        m_sslSocket.startServerEncryption();
    }
    

    It works as long, as the client is only sending information.

    But I would to send results back to the client like

        QByteArray					*block;										// Stream Buffer
    
        block	= new QByteArray;
        QDataStream			outStream(block, QIODevice::ReadWrite);         // just for write only
        outStream.setVersion(QDataStream::Qt_5_4);							// Set the version of stream
    
        switch( m_ParameterType )
            {
            case			LastPosition:                 // error in command
                                break;
            case			CustomerData:                 // get data from the clients car
                                if ( sendCustomerData(inStream) )
                                    {
                                    outStream <<  "OK";
                                    }
                                else
                                    {
                                    outStream << "NK";
                                    }
                                m_sslSocket.write(*block);											// Send data to the Server
                                m_sslSocket.flush();                                               // send out the data to the server now
                                m_StateMachineState=CommunicationFinish;
                                break;
            case			RecordData:                   // write the information into the database
                                break;
            }
    
          delete  block;
    

    And during the function "m_sslSocket.write(*block);" I will get the message "QSocketNotifier: Socket notifiers cannot ..."

    And hint to solve this ?

    Best regards
    R.


  • Lifetime Qt Champion

    Looks like your socket is a member variable of TCPThread which will not be moved to the new thread. You should give it a parent so when calling move to thread it's properly moved along.



  • @SGaist
    Hi,

    maybe is misunderstood your advise.

    I change the parent link of the thread:

        m_task->setParent(0);              << ---add Clear parent information (I guess useless)
        m_task->moveToThread(SSL_thread);
    

    I change the object type from object to object pointer and create the object during creation of the thread.

    class TCPThread : public QThread
    {
    	Q_OBJECT
    
    public:
        TCPThread(int, QSqlDatabase *);                                         // Create a thread object
    	~TCPThread();
    ...
    private:
        QSslSocket      *m_sslSocket;                                            // TCP Socket Pointer
    ...
    };
    
    TCPThread::TCPThread(int socketDS,QSqlDatabase *SQLDatabase)
    {
        m_sslSocket = new QSslSocket();
    ...
    } 
    

    But I still get the message of the "QSocketNotifier".

    What did I misunderstood ?

    Best regards
    R.


  • Lifetime Qt Champion

    It's m_sslSocket that you should give a parent to (i.e. add this in the parenthesis).



  • @SGaist
    Hi,

    I changed it to

    this->m_sslSocket->
    

    Edit: I checked as well, only one thread is running.

    Same result.
    Best regards
    R.


  • Lifetime Qt Champion

    That's not what I suggested.

    Here:

    m_sslSocket = new QSslSocket(this);
    


  • Thanks. That solve this problem.
    Best regards
    R.


Log in to reply
 

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