Keep connection opened for a QThreaded QTcpSocket
-
Hello,
I have adapted the Blocking Fortune Client Example. Here is the code:connectionthread.h
#ifndef CONNECTIONTHREAD_H #define CONNECTIONTHREAD_H #include <QThread> #include <QMutex> #include <QWaitCondition> class ConnectionThread : public QThread { Q_OBJECT public: ConnectionThread(QObject *parent = nullptr); ~ConnectionThread(); void requestNewData(const QString &hostName, quint16 port, const QString &message); void run() override; signals: void newData(const QByteArray &data); void error(int socketError, const QString &message); private: QString m_hostName; quint16 m_port; QString m_message; QMutex m_mutex; QWaitCondition m_cond; bool m_quit; }; #endif // CONNECTIONTHREAD_Hconnectionthread.cpp
#include <QtNetwork> #include "connectionthread.h" ConnectionThread::ConnectionThread(QObject *parent) : QThread(parent), m_quit(false) { } ConnectionThread::~ConnectionThread() { m_mutex.lock(); m_quit = true; m_cond.wakeOne(); m_mutex.unlock(); wait(); } void ConnectionThread::requestNewData(const QString &hostName, quint16 port, const QString &message) { QMutexLocker locker(&m_mutex); m_hostName = hostName; m_port = port; m_message = message; if (!isRunning()) start(); else m_cond.wakeOne(); } void ConnectionThread::run() { m_mutex.lock(); QString serverName = m_hostName; quint16 serverPort = m_port; m_mutex.unlock(); while (!m_quit) { const int Timeout = 3 * 1000; // 3 sec. QTcpSocket socket; socket.connectToHost(serverName, serverPort); if (!socket.waitForConnected(Timeout)) { emit error(socket.error(), socket.errorString()); return; } qDebug() << tr("Sending %1 to the server").arg(m_message); socket.write(m_message.toUtf8()); QByteArray data; if (!socket.waitForReadyRead(Timeout)) { emit error(socket.error(), socket.errorString()); return; } data = socket.readAll(); m_mutex.lock(); emit newData(data); m_cond.wait(&m_mutex); serverName = m_hostName; serverPort = m_port; m_mutex.unlock(); } }In the main code, I connect the thread with
ConnectionThread m_thread; connect(&m_thread, &ConnectionThread::newData, this, &Client::readData); connect(&m_thread, &ConnectionThread::error, this, &Client::displayError); m_thread.requestNewData(m_ip_address, m_port, m_messages[m_msgidC2]); ...It works well so far. Yet, now I need to keep the connection opened, i.e. not reconnect, each time I send a new message (with requestNewData())
I do not know how to modify my code to achieve that.
What I tried is to define the socket as a member of ConnectionThread. Then in the run() function, I call socket.connectToHost() only if socket.state() is not equal QTcpSocket::connected.
But doing so, I get message like this one
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x559b0576ae30), parent's thread is QThread(0x559b04f23660), current thread is ConnectionThread(0x559b05582b40)Any idea of design?
-
Hello,
I have adapted the Blocking Fortune Client Example. Here is the code:connectionthread.h
#ifndef CONNECTIONTHREAD_H #define CONNECTIONTHREAD_H #include <QThread> #include <QMutex> #include <QWaitCondition> class ConnectionThread : public QThread { Q_OBJECT public: ConnectionThread(QObject *parent = nullptr); ~ConnectionThread(); void requestNewData(const QString &hostName, quint16 port, const QString &message); void run() override; signals: void newData(const QByteArray &data); void error(int socketError, const QString &message); private: QString m_hostName; quint16 m_port; QString m_message; QMutex m_mutex; QWaitCondition m_cond; bool m_quit; }; #endif // CONNECTIONTHREAD_Hconnectionthread.cpp
#include <QtNetwork> #include "connectionthread.h" ConnectionThread::ConnectionThread(QObject *parent) : QThread(parent), m_quit(false) { } ConnectionThread::~ConnectionThread() { m_mutex.lock(); m_quit = true; m_cond.wakeOne(); m_mutex.unlock(); wait(); } void ConnectionThread::requestNewData(const QString &hostName, quint16 port, const QString &message) { QMutexLocker locker(&m_mutex); m_hostName = hostName; m_port = port; m_message = message; if (!isRunning()) start(); else m_cond.wakeOne(); } void ConnectionThread::run() { m_mutex.lock(); QString serverName = m_hostName; quint16 serverPort = m_port; m_mutex.unlock(); while (!m_quit) { const int Timeout = 3 * 1000; // 3 sec. QTcpSocket socket; socket.connectToHost(serverName, serverPort); if (!socket.waitForConnected(Timeout)) { emit error(socket.error(), socket.errorString()); return; } qDebug() << tr("Sending %1 to the server").arg(m_message); socket.write(m_message.toUtf8()); QByteArray data; if (!socket.waitForReadyRead(Timeout)) { emit error(socket.error(), socket.errorString()); return; } data = socket.readAll(); m_mutex.lock(); emit newData(data); m_cond.wait(&m_mutex); serverName = m_hostName; serverPort = m_port; m_mutex.unlock(); } }In the main code, I connect the thread with
ConnectionThread m_thread; connect(&m_thread, &ConnectionThread::newData, this, &Client::readData); connect(&m_thread, &ConnectionThread::error, this, &Client::displayError); m_thread.requestNewData(m_ip_address, m_port, m_messages[m_msgidC2]); ...It works well so far. Yet, now I need to keep the connection opened, i.e. not reconnect, each time I send a new message (with requestNewData())
I do not know how to modify my code to achieve that.
What I tried is to define the socket as a member of ConnectionThread. Then in the run() function, I call socket.connectToHost() only if socket.state() is not equal QTcpSocket::connected.
But doing so, I get message like this one
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x559b0576ae30), parent's thread is QThread(0x559b04f23660), current thread is ConnectionThread(0x559b05582b40)Any idea of design?
@odelaune said in Keep connection opened for a QThreaded QTcpSocket:
while (!m_quit) {
const int Timeout = 3 * 1000; // 3 sec.QTcpSocket socket; socket.connectToHost(serverName, serverPort);Why do you create a new socket on each loop iteration?
Create it once before the loop and also connect before you enter the loop.
Also, all variables needed in the thread should be created inside run() (not as class member). Because only what is created inside run() is inside the thread. -
@odelaune said in Keep connection opened for a QThreaded QTcpSocket:
while (!m_quit) {
const int Timeout = 3 * 1000; // 3 sec.QTcpSocket socket; socket.connectToHost(serverName, serverPort);Why do you create a new socket on each loop iteration?
Create it once before the loop and also connect before you enter the loop.
Also, all variables needed in the thread should be created inside run() (not as class member). Because only what is created inside run() is inside the thread.@jsulm said in Keep connection opened for a QThreaded QTcpSocket:
@odelaune said in Keep connection opened for a QThreaded QTcpSocket:
while (!m_quit) {
const int Timeout = 3 * 1000; // 3 sec.QTcpSocket socket; socket.connectToHost(serverName, serverPort);Why do you create a new socket on each loop iteration?
Create it once before the loop and also connect before you enter the loop.
Also, all variables needed in the thread should be created inside run() (not as class member). Because only what is created inside run() is inside the thread.For now, I tried to move this code snippet
const int Timeout = 3 * 1000; // 3 sec. QTcpSocket socket; socket.connectToHost(serverName, serverPort); if (!socket.waitForConnected(Timeout)) { emit error(socket.error(), socket.errorString()); return; }just before the while loop. Yet, doing so, the first message is well sent (it is received by the server), but when I want to send another message (after the first one), I always exit the while loop because I always enter into if (!socket.waitForReadyRead(Timeout)). Actually, the server never receive the second request.
So something is probably still missing in the code.For now, I do not understand why the second message is not sent. I have checked what the write functions return and it corresponds to the correct number of bytes that are sent. But the server does not receive anything...
If I place the code snippet inside the while loop, all messages are correctly sent...