How to make blocking tcp socket with Qt? - c++

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.

Related

qt serial port memory leak

I use the following code to talk to a USB-serial port device:
#include "masterthread.h"
#include <QtSerialPort/QSerialPort>
#include <QTime>
#include "Windows.h"
#include "Psapi.h"
#include <QDebug>
QT_USE_NAMESPACE
MasterThread::MasterThread(QObject *parent)
: QThread(parent), waitTimeout(0), quit(false)
{
}
MasterThread::~MasterThread()
{
mutex.lock();
quit = true;
cond.wakeOne();
mutex.unlock();
wait();
}
void MasterThread::run()
{
bool currentPortNameChanged = false;
QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(57600);
serial.setStopBits(static_cast<QSerialPort::StopBits>(1));
serial.setDataBits(static_cast<QSerialPort::DataBits>(8));
serial.setParity(static_cast<QSerialPort::Parity>(0));
serial.open(QIODevice::ReadWrite);
//Tell the serial port connected device to start talking
//--------------------------------------
const char init[] = { 0x0d, 0x0d, 0x0d };
serial.write(init, sizeof(init));
const char* cmd = "mavlink stop\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "uorb start";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "sh /etc/init.d/rc.usb\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 4);
serial.waitForBytesWritten(100);
int i = 0;
int j = 0;
forever
{
//Write test data out
//-----------------------------
QByteArray test(2000, 't');
serial.write(test);
bool check = serial.waitForBytesWritten(100);
if (!check)
{
qDebug() << "FAIL: " << j++;
}
if (serial.waitForReadyRead(20))
{
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
qDebug() << response;
}
QThread::msleep(20);
//Print memory usage
//---------------------------------------------------
if (i++ % 10 == 0)
{
PROCESS_MEMORY_COUNTERS memcount;
if (!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) return;
qDebug()<<"----------------------------" << memcount.WorkingSetSize / 1024 << "KB memory used";
}
} // end foever
qDebug() << "Exiting forever loop";
}
with a simple main.cpp as:
#include <QApplication>
#include "masterthread.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MasterThread thread;
thread.start();
return app.exec();
}
But the memory usage keeps increasing, like 5~10MB per hour as if there are some leakage.
The device is suppose to be connected for days and weeks...
What am I doing wrong here? I am on Qt5.6 windows7 debug
Many Qt Components have an implicit dependency on its event loop.
While you are starting the main threads event loop with the call to app.exec(); you are not handling events generated by the QObjects created in the QThread MasterThread thread;. The details and nuances of Event handling in Qt are very well described on this page: https://wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects
But the solution boils down to: if you want to be able to process queued up Qt events in a thread where you are processing some long-running task you should call QCoreApplication::processEvents(); from time to time. This will prevent Qt events from endlessly queueing up.
EDITED after looking on the code Qt 5.7,5.6,5.5 and reading docs.
As an answer is already accepted, I would just add some thoughts here as it's too long for comments.
Keep things short - an answer you accepted is wrong..
There are two sides of the story. And as SO answers often taken 'as it is as long as they work' I'd like to explain myself...
If you look on a code provided - there is nothing wrong with it. All objects are properly stack allocated and should be destroyed automatically.
Point is that QtSerial uses deleteLater() and then a question - how to delete those allocations properly.
If any module/object/code uses deleteLater() it requires an event loop, if deleteLater() called on a thread without event loop, object will be deleted after thread is terminated. As long as there is no event loop running for code above, processEvents will no work.. actually processEvents() is not something which is used for this, because a whole idea to return from the context which is called deleteLater() and have a next run, and that's checked in the Qt Source Code, so calling processEvent() straight after without incrementing loop count will do nothing at all, that's why answer you accepted is totally wrong.
Conclusion:
If any object requires event loop running it should be EXPLICITELY stated in the documentation as there is nothing wrong in using QIODevice in sync mode outside event loop.
So at my opinion,point is - its a bug in the QT Serial itself which I suggest you report.
In general it's really wrong practice for Qt to run never-ending loops..
It's much much better and cleaner to use QObject Worker tactic which is pushed to the thread, have proper even loop running etc.
For small 'threaded' tasks it's much better to use QtConcurrent.
Proper Workaround:
you will have a thread with properly running event loop and a timer firing at 20ms to do your things
// main thread:
class Worker: public QObject {
public:
Worker();
public slots:
onInit() {
// initialize everything
startTimer(20);
}
protected:
void timerEvent(..) {
// do your things every 20ms
}
}
...
QThread * pWorkerThread = new QThread();
pWorkerThread->setObjectName(QString("Serial"));
Worker * pWorker = new Worker();
Worker->setObjectName(QString("Common Storage Impl"));
Worker->moveToThread(WorkerThread);
connect(pWorkerThread, SIGNAL(started()), pWorker, SLOT(onInit()));
connect(pWorkerThread, SIGNAL(finished()), pWorker, SLOT(deleteLater()));
connect(pWorkerThread, SIGNAL(finished()), pWorkerThread, SLOT(deleteLater()));
pWorkerThread->start();
...

Wait for signal while processing other signals

My Qt application talks to a serial device, and occasionally has to wait for this device to send a byte. To accomplish this, I create a new eventloop that exits as soon as there is information available in the serial buffer:
unsigned char MyClass::waitForDevice(int timeout)
{
QEventLoop wait;
connect(d_serial, SIGNAL(readyRead()), &wait, SLOT(quit()));
if (timeout > 0)
QTimer::singleShot(timeout, &wait, SLOT(quit()));
wait.exec();
return static_cast<unsigned char>(d_serial->read(1)[0]);
}
Now the problem is that, while the application is waiting, i.e. while the eventloop is running, I need to be able to communicate to the serial device when a button is pressed in the GUI. Naively, I tried connecting a signal to a slot that does this, but I found that the slot is only executed after the eventloop is terminated.
I tried, without any luck, to have a seperate QThread running that calls qApp->processEvents() in an infinite loop, which is terminated when the eventloop is terminated. This didn't work, and I'm not quite sure why not. What is the canonical way to resolve this?
You're thinking synchronously in a pre-C++1z world. In C++14 (and prior) asynchronous programming, there is mostly no place for a notion of a wait that is implemented as a function that returns when the wait is over (switch-based coroutine hacks excepted). You are also not using the fact that your application is stateful, and the state transitions can be expressed in a state machine.
Instead, you should simply act on data being available. Presumably, your application can be in multiple states. One of the states - the one where you have to wait for input - is simply exited when the input arrives.
The example below uses a simple process-local pipe, but it would work exactly the same if you were using a serial port - both are a QIODevice and emit requisite signals. We start with the project file.
# async-comms-32309737.pro
QT += widgets core-private
TARGET = async-comms-32309737
CONFIG += c++11
TEMPLATE = app
SOURCES += main.cpp
To make things simple, the pipe implementation reuses the QRingBuffer private class from Qt. See this question for more fleshed-out implementation(s).
// main.cpp
#include <QtWidgets>
#include <private/qringbuffer_p.h>
/// A simple point-to-point intra-application pipe. This class is not thread-safe.
class AppPipe : public QIODevice {
Q_OBJECT
AppPipe * m_other { nullptr };
QRingBuffer m_buf;
public:
AppPipe(AppPipe * other, QObject * parent = 0) : QIODevice(parent), m_other(other) {
open(QIODevice::ReadWrite);
}
void setOther(AppPipe * other) { m_other = other; }
qint64 writeData(const char * data, qint64 maxSize) Q_DECL_OVERRIDE {
if (!maxSize) return maxSize;
m_other->m_buf.append(QByteArray(data, maxSize));
emit m_other->readyRead();
return maxSize;
}
qint64 readData(char * data, qint64 maxLength) Q_DECL_OVERRIDE {
return m_buf.read(data, maxLength);
}
qint64 bytesAvailable() const Q_DECL_OVERRIDE {
return m_buf.size() + QIODevice::bytesAvailable();
}
bool isSequential() const Q_DECL_OVERRIDE { return true; }
};
We start with a simple UI, with one button to restart the state machine, another to transmit a single byte that will be received by the client, and a label that indicates the current state of the state machine.
int main(int argc, char *argv[])
{
QApplication a { argc, argv };
QWidget ui;
QGridLayout grid { &ui };
QLabel state;
QPushButton restart { "Restart" }, transmit { "Transmit" };
grid.addWidget(&state, 0, 0, 1, 2);
grid.addWidget(&restart, 1, 0);
grid.addWidget(&transmit, 1, 1);
ui.show();
We now create the simulated device and the client pipe endpoints.
AppPipe device { nullptr };
AppPipe client { &device };
device.setOther(&client);
The state machine has three states. The s_init is the initial state, and is exited after a 1.5s delay. The s_wait state is only exited when we receive some data (a byte or more) from the device in that state. In this example, receiving the data in other states has no effect. The machine is set to restart automatically when stopped.
QStateMachine sm;
QState
s_init { &sm }, // Exited after a delay
s_wait { &sm }, // Waits for data to arrive
s_end { &sm }; // Final state
QTimer timer;
timer.setSingleShot(true);
sm.setInitialState(&s_init);
QObject::connect(&sm, &QStateMachine::stopped, &sm, &QStateMachine::start);
QObject::connect(&s_init, &QState::entered, [&]{ timer.start(1500); });
s_init.addTransition(&timer, SIGNAL(timeout()), &s_wait);
s_wait.addTransition(&client, SIGNAL(readyRead()), &s_end);
To visualize the state machine's progress, we assign the state label's text property in each of the states:
s_init.assignProperty(&state, "text", "Waiting for timeout.");
s_wait.assignProperty(&state, "text", "Waiting for data.");
s_end.assignProperty(&state, "text", "Done.");
Finally, the restart button stops the state machine - it will self-restart then. The transmit button simulates the device sending one byte of data.
QObject::connect(&restart, &QPushButton::clicked, &sm, &QStateMachine::stop);
QObject::connect(&transmit, &QPushButton::clicked, [&]{
device.write("*", 1);
});
We start the machine, enter the event loop, and let Qt follow our directions onwards from here. The main.moc file is included for it contains the metadata for AppPipe.
sm.start();
return a.exec();
}
#include "main.moc"
There are several Types of which Signals and Slots can be connected.
See: http://doc.qt.io/qt-4.8/qt.html#ConnectionType-enum
Have you tried Qt::DirectConnection: connect(d_serial, SIGNAL(readyRead()), &wait, SLOT(quit()),Qt::DirectConnection); ?

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);

Pausing execution until a specific message on a socket is received?

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.

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);
};