I have loop that is supposed to try to connect to each IP from range:
for(...){
socket->connectToHost(addres,port);
do stuff....
if(socket->waitForConnected(2000))
{
do stuff...
if(socket->waitForReadyRead(1000))
{
do stuff...
}
else do stuff...
}
do stuff ......
}
During connection atempts UI freezes, because there is no event processing in the meantime. I tried to add QCoreApplication::processEvents(); inside the loop, however it still freezes for long time during waitForConnected, and I also tried to use timers, but this also wont work as QT needs event processing to use timers in the first place. Is there any way to provide event processing (prevent UI from freezing) during conection, or using some non-blocking alternative for waitForConnection?
The best approach is to use QTcpSocket in an asynchronous mode by connecting the signals of the socket to relevant slots :
connect( socket, SIGNAL(connected()), this, SLOT(onConnected()) );
connect( socket, SIGNAL(readyRead()), this, SLOT(tcpReady()) );
connect( socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(tcpError(QAbstractSocket::SocketError)) );
And handle your application logic in the slots :
void MyClass::onConnected()
{
...
}
void MyClass::tcpError(QAbstractSocket::SocketError error)
{
...
}
You can also use a local event loop using QEventLoop and connect the signals connected, error, ... of your QTcpSocket to the quit slot of QEventLoop. This way when the socket is connected or an error is occured, the local event loop quits and the rest gets executed :
socket->connectToHost(addres,port);
QEventLoop loop;
loop.connect(socket, SIGNAL(connected()), SLOT(quit()));
loop.connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(quit()));
loop.exec();
//...
I should not that it's the standard pattern for "blocking wait without blocking the UI".
Please write out 100 times 'I must not wait in GUI event-handlers'.
Use async signals or thread off the comms.
Related
I want to use a recursive procedure to iterate through a large number of images in Qt: essentially the image is repeatedly quartered (up to a limit) and the user is asked whether the image passes or fails - ie if the image passes at large dimensions we call our function again with smaller dimensions (until we reach the limit), if it fails we return and so pass back up the hierarchy.
This approach seems to run into a roadblock with Qt's event-driven approach - I cannot see how I can pause the loop while waiting for the user input - ie there is nothing like a "wait_for_button_press" method.
I know that this sort of approach is regarded as an anti-pattern in event driven programming, but what is the alternative way that doesn't involve holding lots and lots of state on the heap (as opposed to getting it held for 'free' on the stack)?
QEventLoop maybe could help you. I start a http connection aside a timer with a timeout, all inside a thread. Then a wait for one of those had finish and return.
void MyThread::run(){
QNetworkAccessManager qnaManager;
bool isPost = false;
QUrl url(myUrl);
QNetworkRequest req(url);
QNetworkReply *reply;
req.setHeader(QNetworkRequest::ContentTypeHeader,
"application/json");
req.setHeader(QNetworkRequest::ContentLengthHeader,
QVariant(postData.size()).toString());
reply = qnaManager.get(req);
QEventLoop eventLoop;
QTimer timer;
timer.setSingleShot(true);
const int timeout = 400;
timer.start(timeout);
connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
if (timer.isActive()){
//everything is ok
}else{
//timer elapsed, no replay
return;
}
}
For what it's worth, in the end I decided that the best route was to implement more message passing code - wait for the user input to dispatch a message. It was longer code than if I had used/had available the 'traditional' call back type paradigm, but it worked cleanly in the end.
I am using asio (standalone header only) within a Qt Quick application.
As Qt and asio have both their own event loop if I understood correctly, I use a QTimer signal to call the class that holds my asio::io_service object.
QTimer *timer_io = new QTimer();
QObject::connect(timer_io, SIGNAL(timeout()), &my_INandOUT, SLOT(poll_ios()));
timer_io->start(IO_TIMER);
I have set IO_TIMER to 100 ms. I have read in the documentation that asio::io_service.reset() must be called after each poll(). So the slot poll_ios() has the following code:
void INandOUT::poll_ios()
{
// qDebug() << "poll_io signal";
m_io_service.poll_one();
m_io_service.reset();
}
Is that the correct way to call the reset() ? Or should I call it in each handler once they have finished their task ? Is it safe or could I loose asio events ?
It would be simpler and easier to lose the asio events and use Qt builtin classes instead: e.g: QNetworkAccessManager or QUdpSocket.
However, calling poll_one or poll from a timer (as you have done) is the normal way of using asio with an external event loop.
But I don't recommend calling reset after calling poll_one since according to the documentation it should only be called:
when a previous invocation of these functions returned due to the
io_service being stopped or running out of work
If you re-enable your asio handlers (e.g. enabling a receive handler after receiving a message) then io_service always has work to do. In which case it would be better to just call poll instead of poll_one and lose the call to reset, e.g.:
void INandOUT::poll_ios()
{
// qDebug() << "poll io signal";
m_io_service.poll();
}
Disclaimer: I am relatively new to Qt and any type of programming that revolves around Threads and Networking. I have also adopted a lot of code from Qt Examples, API, and other online examples.
All code can be found on GitHub. This code is relatively as simple as it can get minus striping out GUI. I figure supplying it this way would help as well versus just pasting the code below.
I want to use and believe I need to use Threads as I need multiple clients send a request to the server, the server run some SQL code, then spit out the results back to the client (basically deriving a MySQL Server, but specific to what I am doing). Right now though, I am just working on learning the workings of it all.
With all that being said, as the Title states.. My client can connect to the server, the server sets up the thread, and will receive data (a String) through the readReady. After the data is read in, for right now I am just trying to echo it back to the client. It will do this, but only once. Then it spits out:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x266cca92ea0), parent's thread is serverThread(0x266cca9ed60), current thread is QThread(0x266cac772e0)
I cannot send any further data to the server unless I have the client reconnect, then after the data is sent, it will do its job but then spit out the same error and cease functioning. I have tried quite a bit of different things, but cannot seem to fix the issue. I even tried setting up a SIGNAL/SLOT for this as suggested in API:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
Anyway, any help would be greatly appreciated! My Code is below..
Server
ServerThread.cpp
// Project
#include "ServerDialog.h"
#include "ServerThread.h"
ServerThread::ServerThread(qintptr _socketDiscriptor, QObject *parent /*= 0*/)
: QThread(parent)
{
socketDiscriptor = _socketDiscriptor;
}
void ServerThread::run()
{
emit threadStarted(socketDiscriptor);
// Start Thread
clientSocket = new QTcpSocket;
// Set SocketDisc
if (!clientSocket->setSocketDescriptor(socketDiscriptor))
{
emit error(clientSocket->error());
return;
}
// Connect Socket and Signal
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//// Loop Thread to Stay Alive for Signals and Slots
exec();
}
void ServerThread::readyRead()
{
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_5_7);
in.startTransaction();
QString dataReceived;
in >> dataReceived;
if (!in.commitTransaction())
{
emit readyReadError(socketDiscriptor);
return;
}
emit readyReadMessage(socketDiscriptor, dataReceived);
echoData(dataReceived);
}
void ServerThread::disconnected()
{
emit threadStopped(socketDiscriptor);
clientSocket->disconnect();
clientSocket->deleteLater();
this->exit(0);
}
void ServerThread::echoData(QString &data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
clientSocket->write(block);
}
So in ServerThread.cpp when echoData is called, that is when the error shows up and the Socket ceases functioning.
Any and all help will be appreciated. I know there are a few other posts regarding "Cannot create children for..." in regards to Threads. But I did not find any of them helpful. The one thing that I did find interesting but did not understand was maybe using moveToThread() but a lot of mixed comments on that.
I learn best through code examples along with explanation versus just an explanation or pointer to API. Thank you!
Most of Qt network functions are asynchronous; they do not block the calling thread. There is no need to mess up with threads if you are using QTcpSockets. In fact, creating a thread for every socket is an overkill, since that thread will spend most of its time just waiting for some network operation to finish. Here is how I would implement a single-threaded echo server in Qt:
#include <QtNetwork>
#include <QtCore>
//separate class for the protocol's implementation
class EchoSocket : public QTcpSocket{
Q_OBJECT
public:
explicit EchoSocket(QObject* parent=nullptr):QTcpSocket(parent){
connect(this, &EchoSocket::readyRead, this, &EchoSocket::EchoBack);
connect(this, &EchoSocket::disconnected, this, &EchoSocket::deleteLater);
}
~EchoSocket() = default;
Q_SLOT void EchoBack(){
QByteArray receivedByteArray= readAll();
write(receivedByteArray);
disconnectFromHost();
}
};
class EchoServer : public QTcpServer{
public:
explicit EchoServer(QObject* parent= nullptr):QTcpServer(parent){}
~EchoServer() = default;
//override incomingConnection() and nextPendingConnection()
//to make them deal with EchoSockets instead of QTcpSockets
void incomingConnection(qintptr socketDescriptor){
EchoSocket* socket= new EchoSocket(this);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(qobject_cast<QTcpSocket*>(socket));
}
EchoSocket* nextPendingConnection(){
QTcpSocket* ts= QTcpServer::nextPendingConnection();
return qobject_cast<EchoSocket*>(ts);
}
};
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
EchoServer echoServer;
echoServer.listen(QHostAddress::Any, 9999);
QObject::connect(&echoServer, &EchoServer::newConnection, [&](){
EchoSocket* socket= echoServer.nextPendingConnection();
qDebug() << "Got new connection from: " << socket->peerAddress().toString();
});
return a.exec();
}
#include "main.moc"
Notes:
This server has the ability to handle more than one client at the same time, since there is no blocking. The thread will just respond to the event that happens with the appropriate action; So, if that event was a new connection, it will create a new EchoSocket object to handle it and prints a statement out to qDebug(), and if that event was receiving something on a previously created socket, the same thread will echo received data back and close the connection. It will never block on a single connection waiting for data to arrive nor it will block waiting for a new connection to arrive.
Since you mention using some SQL queries in response for some connections later in your project. Please avoid threading since an SQL database connection in Qt can be used only from the thread that created it, see docs here. So, You'll have to either create a new database connection for each thread (and thus for each connection) in your application (and this is beyond just overkill), or switch later to a single threaded design.
In this section, I am explaining why threading does not work for you the way you are doing it:
You should not be declaring slots in your QThread subclass, Instead, use worker QObjects and move them to QThreads as needed.
The quote you have provided in your question is the exact explanation for why you get this warning. The ServerThread instance you create will be living in the main thread (or whatever thread that created it). Now let's consider this line from your code:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
The signal readyRead() will be emitted from the current ServerThread instance (since the clientSocket object that emits it lives there), However, the receiver object is the current ServerThread instance, But that lives in the main thread. Here is what the documentation says:
If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
Now, the main point of Qt::QueuedConnection is executing the slot in the receiver object's thread. This means that, your slots ServerThread::readyRead() and ServerThread::disconnected will get executed in the main thread. This is most likely not what you meant to do, since you'll end up accessing clientSocket from the main thread. After that, any call on clientSocket that results in child QObjects being created will result in the warning you get (you can see that QTcpSocket::write() does this here).
Mixed comments of movetothread are linked mostly to usage of it to move thread object to itself.
The quote hints that the members of QThread aren't designed to be called from worker. Strictly proper way to call signal would be by using worker object model, that was shown in Qt examples and explained a few times on QT-related blogs:
class Worker : public QObject
{
Q_OBJECT
private slots:
void onTimeout()
{
qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
}
};
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
};
worker constructed inside run() is "property" of the thread it created, so figuratively speaking, it is slaved to its context. The same effect maybe achieved if you create worker in other thread, then move it to this thread before connection was made. When you connect signal to slot of the QThread itself, you connect child thread to thread it was created by.
Use of
connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection);
or creating connection from your thread sometimes seems to achieve proper result, but not in this case, where you try use objects constructed in different threads together. Calling moveToThread(this) in constructor is a thing not recommended to do.
I'm doing a ping to an IP address, and I want to show into a QMessageBox that a ping operation is going on. After that, if a response is received or one second timeout happens, I want to close the QMessageBox.
Code:
int status;
QByteArray command;
QMessageBox myBox(QMessageBox::Information, QString("Info"), QString("Checking connection"), QMessageBox::NoButton, this);
command.append("ping -w 1 172.22.1.1");
status=system(command);
myBox.setStandardButtons(0);
myBox.exec();
if (0==status){ // Response received
// Some stuff here...
myeBox.setVisible(false);
}
else { // Timeout
// Some other stuff here...
myBox.setVisible(false);
}
My guess is that I may need to use threads for this task, but since I am a Qt newbie maybe the problem is anywhere else.
EDIT:
As #atamanroman suggested I've tried to use QProcess, using signal void QProcess::finished ( int exitCode, QProcess::ExitStatus exitStatus ) [signal] as told in Qt reference:
private:
QProcess *process;
//...
QMessageBox myBox(QMessageBox::Information, QString("Info"), QString("Checking connection"), QMessageBox::NoButton, this);
QObject::connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &myBox, SLOT(close()));
command.append("ping -w 1 172.22.1.1");
process.start(comdand);
myBox.setStandardButtons(0);
myBox.exec();
And it's not working. myBox is never closed. What's wrong?
You should use QProcess (start ping.exe and parse output) or QTcpSocket (do the ping yourself) instead of system() because they are part of Qt and can signal you when the ping has finished. Connect to that signal in order to hide your QMessageBox.
In your edit:
First:
QProcess *process; // This is a pointer, you don't need to add "&" in connect
// You should have called "process = new QProcess" before...
QMessageBox myBox; // This is an object, you need to add the "&" to connect;
We take out the first &
QObject::connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), &myBox, SLOT(close()));
second:
Using Linux ping will never stop, then you will never have the finished signal. You can provide ping some parameters like count or time to wait. Or start a timer to stop the process.
third:
You need to match the parameters between signals and slots to avoid warnings, etc.
I sugest you to create a local SLOT "processfinished(int, QProcess::ExitStatus)" and then you call to myBox.Close(), but "myBox" must be from class to have reference to this after end the method where you call it.
What would I need to receive data from a client?
QTcpServer Server;
if(!Server.listen("127.0.0.1", 9000)) {
return;
}
connect(Server, SIGNAL(newConnection()), this, SLOT(ReceiveData()));
Is this correct so far? What do I need in ReceiveData? Do I really need another function to receive the data? I would like to save it in a QByteArray
Thanks
As this hasn't been answered, here's a really basic example.
In your ReceiveData slot, you would need to accept the connection from the server.
In Qt's QTcpServer this is done by calling nextPendingConnection().
So the QTcpServer's newConnection slot will call your ReceiveData slot.
In your receivedata slot, you can do something like:
void ReceiveData()
{
QTcpSocket *socket = server->nextPendingConnection();
if (!socket)
return;
qDebug("Client connected");
socket->waitForReadyRead(5000);
QByteArray data = socket->readAll();
qDebug(data.constData());
socket->close();
}
Note: This is a blocking example, the waitForReadyRead will hang the thread for up to 5000 milliseconds.
To do a non blocking example, you need to connect another slot to the new socket's readyread signal.
Have you seen this example:
http://doc.qt.io/qt-5/qtnetwork-fortuneserver-server-cpp.html
PS:
Yes, you need at least one callback function to:
1) accept new connections
2) Receive and Send data on the connect(s)