Solved 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. -
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 functionm_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. -
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. -
It's
m_sslSocket
that you should give a parent to (i.e. addthis
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. -
That's not what I suggested.
Here:
m_sslSocket = new QSslSocket(this);
-
Thanks. That solve this problem.
Best regards
R.