Pausing execution until a specific message on a socket is received? - c++

Is there some way to make a function pause it's execution until the socket receives a specific message? Using Signals + QEventLoop to wait doesn't work because while it can wait for signals, there isn't any way to get the data the signal emitted (or is there?).

You could connect to the following signal:
void QIODevice::readyRead() [signal]
Then, you would basically read the data and if it is the one you are looking for, you could set a boolean variable to true that is initially false. Your function would continue the execution only when the variable is true.
Make sure that the function paused is not sleeping in a sync manner too much, etc, without having a dedicated thread.
So, this would be one way of solving your task:
MySocketManager::MySocketManager(QObject *parent): QObject(parent)
{
...
connect(m_mySocket, SIGNAL(readyRead()), SLOT(handleReadyRead()));
...
}
void MySocketManager::handleReadyRead()
{
if (m_mySocket.readAll() == "myMessage")
continue = true;
}
...
void myFunction()
{
...
continue = false;
qDebug() << "Pause";
while (!continue) { ... }
qDebug() << "Continue";
...
}
This is a tad simplication of the issue, but since you have not shown much effort other than asking for solution, this should get you started.

Related

QT: Run a function as long as button is toggled

I want to implement a GUI that receives messages from an external device. The "advancedReceiveExample" is waiting for messages. Once it has received one, it does stuff with it, saves it and terminates.
I want to make my function wait for new messages after receiving one as long as the button is toggled.
I have tried this so far:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
This works perfectly fine but as mentioned above it only receives one message. If I do that:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
while (1)
{
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
it blocks the function because the state of the button can only be change after the function "on_pushButton_clicked()" has terminated.
Visual Studio 2019
C/C++
EDIT: Okay, I have understood the problem of blocking the thread. Multithreading might be the right option but I am very unexperienced regarding this topic. The <QThread> could be possible. How would you use it?
Do you have suggestions which other library could be used?
Note QT is event-based. If you keep your computer busy inside some function without returning to the main loop frequently, your GUI will freeze.
What you need to do is slice your action that you want to do into small bits that can repeatedly return to the main loop in order to keep the GUI responsive. (Another method yould be to swap out your action into a separate thread and handle it in parallel, killing the thread when the button is released)
Probably the simplest method to do what you want is with timers that you arm in the PushButton::clicked slot, and then check in the timer event whether the button is still pressed, and, if yes, do a bit of your action, save state and re-arm the timer to have you return.
Something along the lines of the following pseudo code should work and execute what you want to do in slices every 10ms:
MainWindow::onPushButtonClicked () {
// do the action, or, alternatively, start a
// parallel thread that does it
do_a_bit_of_action();
// sets up a timer to call onTimer after 10ms
QTimer::singleShot (10, this, SLOT(onTimer()));
}
MainWindow::onTimer () {
// check if button is still held down
if (pushButton.down) {
// re-arm timer
Timer::singleShot (10, this, SLOT(onTimer()));
// do some more action bits
do_a_bit_of_action();
}
else {
// kill optional background thread here
}
}
You can try it with:
while(ui.pushButton->isChecked()){
*your function*
}

How to make blocking tcp socket with Qt?

I work with QTcpSocket. I need any write/read calls to the socket to be synchronous (blocking).
I know there is waitForReadyRead() and waitForBytesWritten(), but those two methods are marked in Qt documentation as they can fail randomly under Windows. I cannot affort this.
The blocking read is the most important (as reading comes always after writting a command to the other peer, so I know that if data reaches the other peer, it will answer).
I have tried 2 approaches.
First:
QByteArray readBytes(qint64 count)
{
int sleepIterations = 0;
QByteArray resultBytes;
while (resultBytes.size() < count && sleepIterations < 100)
{
if (socket->bytesAvailable() == 0)
{
sleepIterations++;
QThread::msleep(100);
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
continue;
}
resultBytes += socket->read(qMin(count, socket->bytesAvailable()));
}
return resultBytes;
}
This should wait for bytes to be available for reading on the socket, processing the event loop in the mean time, so the socket is doing it's necessary internal stuff.
Unfortunately - for unknown to me reason - the bytesAvailable() sometimes returns correct number of bytes, but sometimes it never returns anything greater than 0.
I know in fact that there was data to be read, because it used to work with the second approach (but it has it's own problems).
Second:
I have a kind of signal "blocker", which blocks current context and processes event loop, until certain signal is emitted. This is the "blocker":
SignalWait.h:
class SignalWait : public QObject
{
Q_OBJECT
public:
SignalWait(QObject *object, const char *signal);
bool wait(int msTimeout);
private:
bool called = false;
private slots:
void handleSignal();
};
SignalWait.cpp:
SignalWait::SignalWait(QObject* object, const char* signal) :
QObject()
{
connect(object, signal, this, SLOT(handleSignal()));
}
bool SignalWait::wait(int msTimeout)
{
QTime timer(0, 0, 0, msTimeout);
timer.start();
while (!called && timer.elapsed() < msTimeout)
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return called;
}
void SignalWait::handleSignal()
{
called = true;
}
and then I used it like this:
SignalWait signalWait(socket, SIGNAL(readyRead()));
// ...
// socket->write(...);
// ...
if (!signalWait.wait(30000))
{
// error
return;
}
bytes = socket->read(size);
This approach seems to be working better, but it also fails from time to time. I don't know why. It's like the readyRead() signal was never emitted and the SignalWait keeps waiting, until it times out.
I'm out of ideas. What is the proper way to deal with it?
I would suggest to use the asynchronous approach but if you really want to go with the synchronous way, then a better way is to use a local event loop:
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
loop.connect(socket, SIGNAL(readyRead()), SLOT(quit()));
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
while (resultBytes.size() < count)
{
timer.start(msTimeout);
loop.exec();
if(timer.isActive())
resultBytes += socket->read(qMin(count, socket->bytesAvailable()));
else
break;
}
Here it waits until count bytes are read or the the timeout reaches.

qt waitforreadyread() inconsistent?

Under Qt 4.7.1, OS X 10.6.8
(have to use this -- later versions
of Qt and/or OS X introduce severe
incompatibilities for my users)
The following works. Sometimes. Then sometimes not.
When it doesn't work, it returns "Unknown Error"
hst is good in all cases, qDebug returns same correct
data for hst every time.
The idea is, use ->get to pull a CGI URL; the CGI
returns some data, which I can ignore in this case.
Then I'm done.
hst is a well formed URL,
http://yadda.com/cgi-bin/whatever.py
QString hst;
QNetworkReply *qnr;
QNetworkAccessManager *qqnap = NULL;
qqnap = new(std::nothrow) QNetworkAccessManager(tmw);
if (qqnap != NULL)
{
hst = loaduphst(); // get qstring to send
qnr = qqnap->get(QNetworkRequest(QUrl(hst))); // report in and fetch update info
if (qnr->waitForReadyRead(3000) == FALSE)
{
qDebug() << "waitForReadyRead() returned FALSE -- error or timeout:" << qnr->errorString();
}
}
else
{
qDebug() << "qqnap is NULL";
}
yadda.com is up; the target script is dead simple
and works fine from browser or cmd line every time.
This is running within the context of
MainWindow::closeEvent(QCloseEvent *ce)
before I emit ce->accept() GUI is still up,
etc.
Hints? Tips? Abuse? Thanks!
waitForReadyRead is not implemented in QNetworkReply. The default implementation does nothing:
bool QIODevice::waitForReadyRead(int msecs)
{
Q_UNUSED(msecs);
return false;
}
Use the readyRead signal to find out when there is data available to be read.
More-or-less synchronous use of async networking is very problematic in the context of the main GUI loop. Signals that don't appear (finished OR readyRead), URLs that sometimes send and sometimes don't... and of course, as the kind person above pointed out, unimplemented functions. Zebras!
What we can do, though, is fire up an event loop and a timer on our own, and this will in a more-or-less friendly way act synchronous.
Perhaps some poor soul will need to poke a website CGI as I do; here's the code. It works. At least under Qt 4.7.1 it does!
So anyway, here it is:
QNetworkReply *qnr;
QNetworkAccessManager *qqnap;
QNetworkRequest qnwr;
QEventLoop w;
QTimer arf;
if ((qqnap = new(std::nothrow) QNetworkAccessManager(this)))
{
qnwr.setUrl(myUrl()); // Build web goodness
qnwr.setRawHeader("User-Agent", myUserAgent());
arf.setSingleShot(true);
if (connect(&arf, SIGNAL(timeout()), // timer firing blows...
&w, SLOT(quit()) // ...out event loop
) == FALSE)
{ return(BAD_CONNECT_TOUT); }
if (connect(qqnap, SIGNAL(finished(QNetworkReply*)), // notify we finished...
this, SLOT(qqnapReplyQ(QNetworkReply*)) // ...cuz I need to know
) == FALSE)
{ return(BAD_CONNECT_FINISHED_NOTIFY); }
if (connect(qqnap, SIGNAL(finished(QNetworkReply*)), // finishing blows out...
&w, SLOT(quit()) // ...event loop
) == FALSE)
{ return(BAD_CONNECT_FINISHED_ELOOP); }
if ((qnr = qqnap->get(qnwr))) // Go if qnr is good
{
arf.start(6000); // timeout in ms // Watchdog timer on
w.exec(); // handle all that
if (arf.isActive()) { arf.stop(); } // kill timer if needed
}
else { return(BAD_WWWGET); } // FAIL
}
else
{
return(BAD_NWAM); // FAIL
}
return(ZEN_NETWORKING);

When to check for error when using QIODevice's blocking interface (QTcpSocket and QFile)

For learning purposes I made application that sends file across network (which work very well for me). Here I will post main part of code, the code that actually sends bytes, I think that is enough.
My primary question is: When, where, why and how should I check for errors? (looks like more than one question :) )
As you can see, I checked for errors by checking return values of every function that can warn me that way (I marked every check with number to make easier to those who want to help to answer and explain).
Is this necessary? Because it can expand code significantly.
Secondary question:
Is this what I made OK, is there a better way to do it?
while(!file->atEnd()){
if(isCancelled())//this is in a thread, and there is mechanism to cancel it
return;
if((readed = file->read(inter_buffer,BUFLEN)) == -1){ //1 <- marking check with "1"
emit errorOccurred(tr("Error while reading file."));
return;
}
if(socket->write(inter_buffer,readed) == -1){//2 QTcpSocket::write
emit errorOccurred(tr("Unable to send data. Probably the other side cancelled or there are connection problems."));
qDebug() << socket->error();
return;
}
rsofar += readed;
if(!socket->flush()){//3
emit errorOccurred(tr("Unable to send data. Probably the other side cancelled or there are connection problems."));
return;
}
//emit signal to inform GUI thread about progress
emit updateProgress((int)(((double)rsofar)/(double)filesize * 100.0));
if(!socket->waitForBytesWritten()){//4
//maybe this is not the right message, but that is not important now
emit errorOccurred(tr("Unable to send data. Probably the other side cancelled or there are connection problems."));
return;
}
}
Đ¢ertiary question is: In Java I would rely on Exceptions to handle this kind of problems. Why Qt functions does not throw exceptions? Is it because it is considered slow for C++ (because of stack unrolling), or just bad habit when programming in C++, or because it does not work well with signals and slots, or something else?
Exceptions can add memory and runtime overhead on some C++ implementations. It's not a problem on modern, well maintained C++ implementations - but Qt has to run and compile on some really obsolete or awkward platforms. Not only that - Qt (at least the core) has to compile and run properly with compiler's exception support disabled.
Your error code checking is almost correct. In your case, if write returns any size other than readed, it should be treated as an error. Grammar nitpick: the correct form is "read", not "readed". Yes, you have "written" but simply "read". English is weird like that ;)
There is no need to use flush(). Just waitForBytesWritten and then check how many bytes still remain to be written and report progress based on that. You're making things run slower since your approach can't amortize the latency of disk file access: you don't do network sending and file reading in parallel.
So, what you're doing is somewhat convoluted. You don't need to use blocking waitForX functions at all. You're running in a thread, so let's just use signals provided by QIODevice and use the default event loop that QThread's run() method is spinning. That way you can process multiple files in the same worker thread. Your implementation requires a dedicated thread for each file processed in parallel.
The code below should work. Simply use moveToThread to move it to a worker QThread - don't derive from QThread. To start sending, invoke the start() slot. To cancel sending, all you need to do is to call sender->deleteLater().
#include <QTcpSocket>
#include <QByteArray>
class Sender : public QObject {
Q_OBJECT
QIODevice * m_src;
QAbstractSocket * m_dst;
QByteArray m_buf;
qint64 m_hasRead;
qint64 m_hasWritten;
qint64 m_srcSize;
bool m_doneSignaled;
bool signalDone() {
if (!m_doneSignaled &&
((m_srcSize && m_hasWritten == m_srcSize) || m_src->atEnd())) {
emit done();
m_doneSignaled = true;
}
return m_doneSignaled;
}
Q_SLOT void dstBytesWritten(qint64 len) {
if (m_dst->bytesToWrite() < m_buf.size() / 2) {
// the transmit buffer is running low, refill
send();
}
m_hasWritten += len;
emit progressed((m_hasWritten * 100) / m_srcSize);
signalDone();
}
Q_SLOT void dstError() {
emit errorOccurred(tr("Unable to send data. Probably the other side"
"cancelled or there are connection problems."));
qDebug() << m_dst->error();
}
void send() {
if (signalDone()) return;
qint64 read = m_src->read(m_buf.data(), m_buf.size());
if (read == -1) {
emit errorOccurred(tr("Error while reading file."));
return;
}
m_hasRead += read;
qint64 written = m_dst->write(m_buf.constData(), read);
if (written == -1) {
emit errorOccurred(tr("Unable to send data. Probably the other side "
"cancelled or there are connection problems."));
qDebug() << m_dst->error();
return;
}
if (written != read) {
emit errorOccurred(tr("Internal error while filling write buffer."));
qDebug() << m_dst->error();
return;
}
}
public:
/*! Requires a source device open for reading, and a destination socket open
for writing. */
Sender(QIODevice * src, QAbstractSocket * dst, QObject * parent = 0) :
QObject(parent), m_src(src), m_dst(dst), m_buf(8192, Qt::Uninitialized),
m_hasRead(0), m_hasWritten(0), m_doneSignaled(false)
{
Q_ASSERT(m_src->isReadable());
Q_ASSERT(m_dst->isWritable());
connect(m_dst, SIGNAL(bytesWritten(qint64)), SLOT(dstBytesWritten(qint64)));
connect(m_dst, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(dstError()));
m_srcSize = m_src->size();
}
Q_SLOT void start() { send(); }
Q_SIGNAL void done();
Q_SIGNAL void errorOccurred(const QString &);
Q_SIGNAL void progressed(int percent);
};

Qt QTimer is it safe to stop it this way?

Is it safe to stop Qt's timer in it's "timeout" signal/slot function?
Can't seem to find any information in Qt documentation about the QTimer.
I have created a timer that is periodically sending a "keep alive" messages to the server.
I want this timer to be stopped if there is some kind of error while sending my message.
private:
QTimer* mpKeepAliveTimer;
Timer is initialized like this:
mpKeepAliveTimer = new QTimer(/* this */);
QObject::connect(mpKeepAliveTimer, SIGNAL(timeout()), this, SLOT(OnKeepAlive()));
mpKeepAliveTimer->start(KEEP_ALIVE_PERIOD);
Stopped like this:
if (mpKeepAliveTimer != NULL) // <-- Edited
{
if (mpKeepAliveTimer->isActive() == true)
mpKeepAliveTimer->stop();
delete mpKeepAliveTimer;
mpKeepAliveTimer = NULL;
}
Timeout function looks like this:
void Classname::OnKeepAlive()
{
if (isErrorFound == true)
mpKeepAliveTimer->stop(); // <---- IS THIS SAFE?
}
Thanks.
As long as you are not explicitly using Queued Connections, this is safe.
This is because the emit timeout() function will not return until all the slots it's connected to were processed.
If you were however using Queued Connections, it could in theory happen that there are still unprocessed timeout events in the Event Queue, so to make it hyper-safe you could use the following:
void Classname::OnKeepAlive()
{
if (!mpKeepAliveTimer || !mpKeepAliveTimer->isActive()) return;
if (isErrorFound)
{
mpKeepAliveTimer->stop();
}
}
Note that the condition in your stop function should be != NULL instead of == NULL. You can also write that function as follows, however:
if (mpKeepAliveTimer)
{
delete mpKeepAliveTimer;
mpKeepAliveTimer = NULL;
}
As already suggested in the comments, QTimer will stop itself in its destructor.