Solved QSslSocket::readyRead() signal is not raise after sending data ..
-
@aha_1980
The thing is, he claims that he does not receive signal at all unless he includeswaitForReadyRead()
. Or that is how I took his question. If that is the case, he does not get as far as that code, so although it's bad it's not executed. -
@JNBarchan said in QSslSocket::readyRead() signal is not raise after sending data ..:
If that is the case, he does not get as far as that code, so although it's bad it's not executed.
That's what he said. But in programming, I don't believe anymore, I just verify. And I'm pretty sure his slot does not get over the while loop in the slot.
Of course you may also be right that the event loop is not running at all. We'll see when we get more information.
-
@aha_1980 said in QSslSocket::readyRead() signal is not raise after sending data ..:
@JNBarchan said in QSslSocket::readyRead() signal is not raise after sending data ..:
That's what he said. But in programming, I don't believe anymore, I just verify.I couldn't agree with you more. But then I get into trouble! :)
-
The thing is, he claims that he does not receive signal at all unless he includes waitForReadyRead()
Thats correct, If I remove the line "waitForReadyRead()", I do not get the event "ReadyRead".
Best regards
R. -
@Ritchie said in QSslSocket::readyRead() signal is not raise after sending data ..:
Thats correct, If I remove the line "waitForReadyRead()", I do not get the event "ReadyRead".
And have you checked our hints?
If your slot is connected, and the data comes in, the slot is called. So your problem must be somewhere else in your program. Really make sure you block then event loop, this is the most common reason for problems like yours.
As you gave us only snippets of your program, this is the max. help we can give you.
PS: And make sure you don't call blockSignals() - this was the reason for a timer not calling it's slot some days ago in this forum.
-
@Ritchie said in QSslSocket::readyRead() signal is not raise after sending data ..:
m_sslSocket->write(*block); m_sslSocket->flush(); m_StateMachineState=CommandSend; m_sslSocket->waitForReadyRead(10); delete block;
I believe you delete your
block
before write is finished, write is asynchronus after all.Try replacing
delete block
with://With the assumption block is a Qbytearray connect(m_sslSocket, &QSslSocket::bytesWritten, block, &QByteArray::deleteLater);
-
@J.Hilk
Since he callsm_sslSocket->flush();
, and that says "This function writes as much as possible from the internal write buffer to the underlying network socket, without blocking", I'm assuming that we don't have an asynchronous/out of scope situation onblock
?Having said that, I'm not defending the design pattern, just questioning whether it will actually go wrong. Your
deleteLater
is a nicer pattern. -
@JNBarchan
Well we can narrow it down a bit by replacing waitForReadyRead withbool QIODevice::waitForBytesWritten(int msecs)
and monitoring the time spend waiting:QElapsedTimer eT; et.start(); m_sslSocket->write(*block); m_sslSocket->flush(); m_StateMachineState=CommandSend; qDebug() << m_sslSocket->waitForBytesWritten(10) << "Time since write" << et.elapsed() << et.nsecsElapsed(); delete block;
-
@Ritchie
At this point, unless you show/explain what your code does after the snippet you show (if you don't do them_sslSocket->waitForReadyRead(10)
), in the way of hitting an event loop, I don't think people can help you further.Alternatively, if you don't want to do that, I also suggested that a possible "workaround" in practice might be
m_sslSocket->waitForReadyRead(0)
), but you haven't commented on trying that either. -
Thanks to all,
I will update my program with your recommendations and come back
with results.Best regards
R. -
Hi to all,
@aha_1980
I change the waiting function toif( m_sslSocket->bytesAvailable() < 6 ) return;
This works as well and will not block.
Thanks for this info.Of course you may also be right that the event loop is not running at all. We'll see when we get more information.
Is the event Loop for each thread or the complete system,
because I have also run a front end and a second thread reading sensor values.PS: And make sure you don't call blockSignals() - this was the reason for a timer not calling it's slot some days ago in this forum.
I do not use "blockSignals() " in my source code. Are there know functions of QT, which are using this function ?
I believe you delete your block before write is finished, write is asynchronus after all.
Transmission to the server is working fine, since the connection is established.
@JNBarchan
waitForReadyRead(0) does not work.
I check the value 5, which will work as the smallest value.
But up to now, I am working locally and the server has to
do a query in the database for the answer.
See what happen later in real envirement (internet via mobil to the server).Your deleteLater is a nicer pattern.
When I use deletelater, at which time will QT delete the object,
because the function is call several times in a minute.Here is the complete code of the client
// // C++ Implementation: Datathread // // Description: // // // Author: // // Copyright: See COPYING file that comes with this distribution // // #include <QDebug> #include <QSettings> #include <QMessageBox> #include <QThread> #include "ProgramDiagnose.h" #include "DataThread.h" extern QString ApplicationPath; // Path of the exe File class SensorValueData; // ************************************************************ // Constructor // ************************************************************ DataThread::DataThread(int *PPointer,SensorValueDatas *SensorBufferPointer, ProgrammDiagnosis *DebugPointer) { m_ProgramIsRunning = PPointer; SensorQueryBuffer = SensorBufferPointer; ProgramInfo=DebugPointer; m_StateMachineState=NoConnection; loadSystemSettings(); } // ************************************************************ // Destructor // ************************************************************ DataThread::~DataThread() { } // ************************************************************************** // Load the system settings of the thread // ************************************************************************** void DataThread::loadSystemSettings(void) { QSettings settings(ApplicationPath + "../config/carinfo.ini",QSettings::IniFormat); settings.beginGroup("DataServer"); m_ServerTCPIPAddress =settings.value("IP", "localhost").toString(); // Car Server Name m_ServerTCPIPPort =settings.value("Port", "localhost").toInt(); // Name of the SQL Database; m_LocalSSLCertificate =settings.value("SSLCertificate", "sslserver.pem").toString(); // settings.endGroup(); settings.beginGroup("CustomerInfo"); m_CustomerID =settings.value("CustomerID", "-").toInt(); // Customer ID m_SerialNumber =settings.value("SerialNo", "-").toString(); m_CarType =settings.value("CarType", "-").toString(); settings.endGroup(); } // ************************************************************ // Send out a record data set // ************************************************************ void DataThread::sendRecordData(void) { QByteArray *block; // Stream Buffer SensorValueData *TempValue; m_blockSize=0; // clear the record size value m_NumberOfBytesSend=0; // Clear the number of byte send TempValue = SensorQueryBuffer->getIndex(0); block = new QByteArray; // create Stream Buffer m_Command.clear(); m_ParameterType=RecordData; m_Command.addParameter((int)m_ParameterType); m_Command.setCommand(TCPIP_CMD_REQUEST_DATA); // data will be send to the server QDataStream outStream(block, QIODevice::ReadWrite); // just for write only outStream.setVersion(QDataStream::Qt_5_4); // Set the version of stream outStream << (m_blockSize); // Reserve memory for size outStream << m_Command ; // Setup the command outStream << *TempValue; // send out the Data outStream.device()->seek(0); // jump back to the start of the block m_blockSize = (quint64)block->size(); outStream << m_blockSize; // write the size of data - size info into m_sslSocket->write(*block); // Send data to the Server m_sslSocket->flush(); // send out the data to the server now m_StateMachineState=CommandSend; // m_sslSocket->waitForReadyRead(5); delete block; } // ************************************************************ // Run function of the thread // ************************************************************ void DataThread::doWork(void) { ProgramInfo->writelog(QObject::tr("carclient"),QObject::tr("DataThread"),QObject::tr("Info"),QObject::tr("Thread startup")); m_sslSocket=new QSslSocket(this); connect(m_sslSocket,SIGNAL(disconnected(void)), this,SLOT(disconnected(void))); connect(m_sslSocket,SIGNAL(encrypted(void)), this, SLOT(SSLReady(void))); typedef void (QSslSocket::* sslErrorsSignal)(const QList<QSslError> &); connect(m_sslSocket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors),this, &DataThread::SSLError); connect(m_sslSocket,SIGNAL(readyRead(void)), this,SLOT(SocketReadyRead(void))); connect(m_sslSocket,SIGNAL(aboutToClose(void)), this,SLOT(aboutToClose(void))); // connect(m_sslSocket,SIGNAL(bytesWritten(qint64)), this,SLOT(bytesWritten(qint64))); m_sslSocket->addCaCertificates(ApplicationPath + "../config/" + m_LocalSSLCertificate); if (! QSslSocket::supportsSsl()) { ProgramInfo->writelog(QObject::tr("carclient"),QObject::tr("DataThread"),QObject::tr("Failure"),QObject::tr("No support fpr SSL connection!")); } QThread::msleep(4000); // Wait a little bit // m_sslSocket->ignoreSslErrors(); while( *m_ProgramIsRunning == true ) // wait until program is close down { if( SensorQueryBuffer->Size() > 0 ) { if ( ! SensorQueryBuffer->locked() ) { if (m_sslSocket->state() != QTcpSocket::ConnectedState) { if( m_StateMachineState == NoConnection ) { m_StateMachineState=TryToConnect; m_sslSocket->connectToHostEncrypted(m_ServerTCPIPAddress, m_ServerTCPIPPort); m_sslSocket->waitForEncrypted(-1); } } } } } if( m_StateMachineState != NoConnection ) { m_sslSocket->close(); m_sslSocket->disconnectFromHost(); } emit WorkFinished(); } // ************************************************************ // Connection was disconnected // ************************************************************ void DataThread::disconnected(void) { SensorQueryBuffer->clearLock(); // release lock of the data m_StateMachineState=NoConnection; // State to disconnected } // ************************************************************ // Host is found from Client // ************************************************************ void DataThread::hostFound(void) { } // ************************************************************ // SSL Connection established // ************************************************************ void DataThread::SSLReady(void) { if( m_StateMachineState !=CommandSend ) { m_StateMachineState=SocketConnected; SensorQueryBuffer->setLocked(); sendRecordData(); // Send out the data } } // ************************************************************ // We get a new connection. Send out the command // ************************************************************ void DataThread::connected(void) { } // ************************************************************ // There was a error inbetween the transmission // ************************************************************ void DataThread::SSLError(const QList<QSslError> errors) { m_LastErrorMessage=m_sslSocket->errorString(); // m_sslSocket->ignoreSslErrors( ); SensorQueryBuffer->clearLock(); m_sslSocket->disconnectFromHost(); m_StateMachineState=NoConnection; // State to disconnected m_sslSocket->close(); ProgramInfo->writelog(tr("carclient"), tr("DataThread"), tr("Error on Connection %3"), tr("Data Background Abort 1 Function (%1::%2)!").arg(m_ServerTCPIPAddress).arg(m_ServerTCPIPPort).arg(m_LastErrorMessage)); // emit showMessageFromThread(tr("Critical System Error"), // tr("DataThread (%1::%2)!").arg(m_ServerTCPIPAddress).arg(m_ServerTCPIPPort), // tr("Error %1 on Connection !").arg(m_LastErrorMessage), // (int)QMessageBox::Critical ); } // ************************************************************ // Client receiveds byte from Server // ************************************************************ void DataThread::SocketReadyRead(void) { QByteArray block; if( m_sslSocket->bytesAvailable() < 6 ) return; QDataStream inStream(m_sslSocket); // Create a data stream by tcp/ip inStream.setVersion(QDataStream::Qt_5_4); // we are using version .. for Transmission inStream >> block; QString sAnswer(block.data()); switch(m_ParameterType) { case NoParameter: break; case RecordData: if(sAnswer == "OK") { SensorQueryBuffer->remove(0); // remove value only if transmitted } SensorQueryBuffer->clearLock(); // release lock of the data break; case CustomerData: break; case LastPosition: break; } m_sslSocket->disconnectFromHost(); m_sslSocket->close(); m_StateMachineState=NoConnection; } // ************************************************************ // Connection is about to close // ************************************************************ void DataThread::aboutToClose(void) { m_StateMachineState=NoConnection; // State to disconnected SensorQueryBuffer->clearLock(); // release lock of the data } // ************************************************************ // Do we have send out all datas to the server // ************************************************************ void DataThread::bytesWritten(qint64 NumberOfBytes) { m_NumberOfBytesSend += NumberOfBytes; if(m_NumberOfBytesSend == m_blockSize) { switch(m_ParameterType) { case NoParameter: break; case RecordData: break; case CustomerData: break; case LastPosition: break; } } }
Best regards
R. -
Hi,
Out of curiosity, why allocate block on the heap ? Since you delete it anyway at the end of the function, just allocate it on the stack. You'll avoid all the troubles you had with deleting it by hand before it was completely sent.
-
@Ritchie:
I just saw from your last code that you also havem_sslSocket->waitForEncrypted(-1);
. In principle, I would avoid mixing thewaitForXxx()
functions with the signal-slot mechanism.I also just recognized, that your code runs within a thread, correct? Using blocking functions is totally valid in threads, but as said above, I'd not mix this with signals-slots.
Further, a thread does not use the event loop of your main program. If you want to use slots in your thread, than you need to implement an event loop for it. Emitting signals from within you thread (e.g. to the main thread) is always possible, but using slots within your thread needs an separate event loop.
And maybe this is already the problem why your slot is only called when you have the
waitForReadyRead()
function active? -
@aha_1980
But when I remove the linem_sslSocket->waitForEncrypted(-1);
the complete communication will not established.
This was posted here:
https://forum.qt.io/topic/84370/create-a-ssl-connection-only-with-slots-and-signalsThere is also a sample program posted (download because of to big files).
I do not get the "encrypted()" signals in this case and I do not know, why.
But with the "m_sslSocket->waitForEncrypted(-1);" I got the signal.Best regards
R. -
Hi,
I just reinstall the complete system to make sure that it is not my installation.
But the problem is still existing.- The server program receives a request for a new connection and start a new instance of the SSLSocket.
But after the command
m_sslSocket->startServerEncryption();
on the server nothing happens on the client. Still!
But now I at a slot
connect(m_sslSocket,SIGNAL(connected(void)), this, SLOT(ConnectionEstablished(void)));
and noticed, that when I close my frontend application which is working
like the sample application of QML, here the start code of the windowQCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); app.setOrganizationName(CLIENT_PROGRAM_NAME); QTextCodec::setCodecForLocale( QTextCodec::codecForName("UTF-8") ); QLocale::setDefault(QLocale::German); QQuickStyle::setStyle(QStringLiteral("qrc:/qml/Style")); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("BackEnd", &UserDisplay); engine.load(QUrl(QStringLiteral("qrc:/client.qml")));
i receive a "Connected" signal.
That sounds for my, that my QML Application is blocking signals, which I do not know.
Is it allow to have a front end, like the sample program and running a back ground program for communication ?
Best regards
R. -
@Ritchie we already gave you some pointers.
Again: don't mix
waitForReadyXxxx()
with signals&slots!If your complete program is not working, its often best to start from scratch with a minimal working example. then build your way to a full program. when you stuck, ask specific questions, we may then be able to help you. most often you can answer you question yourself already.
-
Hi,
Again: don't mix waitForReadyXxxx() with signals&slots!
I do not use any "waitForReadyXxxx()" within my program.
I used once "m_sslSocket->waitForReadyRead(10);" to show, that suddenly a change was happen. But it solve not my problem.Anyways I guess the main reason why it does not work it,
that I have to call "QThread:exec()" with the thread once to support signal and slots in the QThread.But when I call "QThread:exec()" I will not execute any other code in the class.
But I would like to execute the loop which is coded in the function "void DataThread::doWork(void)"
How can I execute "void DataThread::doWork(void)" and let "Qthread:exec()" have at the same time ?
Best regards
R. -
You should take a look at the example provided in the QThread details documentation more specifically the one for the worker object implementation.
-
Hi,
I am already using the first way, shown in the examples.
But the documents says:
A QThread object manages one thread of control within the program. QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread.
So, if I not execute the "Exec()" command, so far I understand, the QT Event Loop will not starts.
But within the examples, there is no using any "exec()".
It says for the first sample:
The code inside the Worker's slot would then execute in a separate thread. However, you are free to connect the Worker's slots to any signal, from any object, in any thread. It is safe to connect signals and slots across different threads, thanks to a mechanism called queued connections.
So in this case, no "exec()" is needed in the separate thread to execute ?
And for the second sample it says
In that example, the thread will exit after the run function has returned. There will not be any event loop running in the thread unless you call exec().
Best regards
R. -
@Ritchie I'm assuming your "program" is a client connecting securely to a server, because you're using
m_sslSocket->write(*block); m_sslSocket->flush();
so I don't getting why you're expecting a readyRead() signal, since that will happen when you are reading data, not writing it. From Qt's documentation:
void QIODevice::readyRead()
This signal is emitted once every time new data is available for reading from the device's current read channel.
Am I missing something? If so my apologies right now...