PDA

View Full Version : QTcpServer(this)



DAVC
19th March 2018, 13:01
Hello everyone.

I have been assigned with the responsibility of maintaining some old Qt program.
In the process i had to convert it from Qt 4 to Qt 5.10 and from Qwt 4.x.x to Qwt 6.1.3

Everything seemed to work and i can compile and run the program.
However, when the server is set up to listen on the corresponding ports, new_Connection() is never called.

I get the following warning:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is gui::model::Listener(0x2ba442c0), parent's thread is QThread(0x215f97b8), current thread is QThread(0x2ba445b0)

More specifically (see code below) the line

server_ = new QTcpServer(this);
is causing it.
I have a strong feeling that it's because
Listener is not in the same thread as
server_

I have search the internet thin, but I cannot seem to find any post that has relevance (or they are too old)



#include <QtNetwork>
#include <QtDebug>
#include "listener.h"
#include "sockethandler.h"
#include <qthread.h>

// Assertion to ensure that char and short has the expected sizes
// (required for protocol to work)

namespace gui { namespace model {
Listener::Listener(QObject *parent, int port) :
QObject(parent), port_(port), server_(0)
{ }

/**
* Create server and listen for connections
*/
void Listener::listen() {
if (server_!=0) qFatal("listen() called on a connection that was already initialized");
server_ = new QTcpServer(this);
server_->listen(QHostAddress::Any, port_);
qDebug() << connect(server_, SIGNAL(newConnection()),
this, SLOT(new_Connection()));
emit log(tr("Listening on port %1").arg(port_));
}

/**
* Called on new connection.
* Check for duplicate and initialize socket.
*/
void Listener::new_Connection()
{
while (server_->hasPendingConnections()) {
emit log(tr("Connection opened on port %1").arg(port_));
emit connected(
new SocketHandler(this, server_->nextPendingConnection())
);
}
}
}} // gui::model



Writing
server_ = new QTcpServer(); instead of
server_ = new QTcpServer(this);
removes the warning, but the problem persists.

.h file:

#ifndef CONNECTION_H
#define CONNECTION_H

#include <QObject>

#include "connectassert.h"

QT_BEGIN_NAMESPACE
class QTcpServer;
class QTcpSocket;
QT_END_NAMESPACE

namespace gui { namespace model {
class SocketHandler;
/**
* Listens on a single port for a connection from HAsim.
*/
class Listener : public QObject {
Q_OBJECT
public:
/** Creates object */
explicit Listener(QObject *parent, int port);
/** Listens for connections */
void listen();

signals:
/** Emitted when a connection is opened */
void connected(SocketHandler*);
/** Emitted when there is information available about connection */
void log(QString str);

private slots:
void new_Connection();

private:
int port_;

QTcpServer *server_;
};

}} // gui::model

#endif // CONNECTION_H


So how can I correctly fix the error?

EDIT: I forgot to add - This worked before (on Qt4), so what is changed from Qt4 to Qt5.10 that would cause this to fail?

I hope you can help

best regards
David

high_flyer
20th March 2018, 09:48
I would say that your SocketHandler creation is probably taking place in a different thread.
Try this see if it helps:


void Listener::new_Connection()
{
while (server_->hasPendingConnections()) {
emit log(tr("Connection opened on port %1").arg(port_));
emit connected(
new SocketHandler(nullptr, server_->nextPendingConnection())
);
}
}


If this gets rid of the error, the you still will have to write some code to take care of the SocketHanlder deletion when you don't need it any more.

Alternatively, the other thread issue is in your SocketHandler.
Can you show your SocketHandler code?

DAVC
20th March 2018, 11:35
Thank you High_Flyer

I can try, but I don't think it will help, as "new_Connection()" is never called. The signal "newConnection" is never emitted.

I should probably elaborate a little further.
The program written in Qt is a GUI (lets call it ServerGUI) meant for measuring and plotting realtime data delivered by a simulator (lets call it SIM).
ServerGUI listens on port 3500 and 3501. I have verified this through debugging and netstat.
Even SIM can see that ServerGUI listens on these ports, thus delivers the data to port 3500 and port 3501, however, it is as if ServerGUI never registers or accepts this connection.

SIM is a 32-bit program, ServerGUI is built using MingW 32-bit in Qt Creator. I am working on a 64-bit Windows 10 machine. (I am writing this because other people with a "somewhat" same issue, mentioned different bit-versions as a possible problem)

Best Regards
David

high_flyer
20th March 2018, 14:08
Can you show the code surrounding the call to listen() on a Listener instance?
Is there anything being moved to different threads there?

Respectively look for all the places in the code threads are involved.

DAVC
21st March 2018, 08:24
Yes,
here is where listen from Listener is being called:


void Server::listen() {

dataListener_ = new Listener(this,DATA_PORT);
connectSignals(dataListener_);
dataListener_->listen();

ctrlListener_ = new Listener(this,CTRL_PORT);
connectSignals(ctrlListener_);
ctrlListener_->listen();

}


The hierachy is:
Main===>model_.listen() ===> server_->listen() ===> Listern->listen()

If you are talking about Qthread, it is not used anywhere in the code.

Best Regards
David

high_flyer
21st March 2018, 09:42
Based on the code you posted, I can't see where the problem is.
Probably a wider code scope is needed to see where the problem is.
Somewhere, use of threads is made - the question is where.

DAVC
21st March 2018, 10:59
Thank you for your time.

I will try some different solutions.
I have some leads i will follow (I only work on this project on mondays)

I will (unlike the many forums i have searched) report back with the solution when i find it, so others who may run into the same problem has a chance.

Best Regards
David

high_flyer
21st March 2018, 11:08
I will (unlike the many forums i have searched) report back with the solution when i find it, so others who may run into the same problem has a chance.

That will be very appreciated!
We encourage it here!

DAVC
26th March 2018, 10:39
I have returned as promised.
I have to be completely honest though, I don't rightly know what exactly fixed it.

I had some notion that it was related to loading incorrect dll-files (libraries), as I had investigated the possibility of building my application with static linking instead of dynamic linking.
In my project I also use Qwt 6.1.3.
So, to make sure there were no lose ends, I recompiled the Qwt library, following the instructions (http://qwt.sourceforge.net/qwtinstall.html) to the letter.
However, linking to the new location of the newly compiled Qwt library was challenging. Everywhere i searched everyone said the syntax was:

LIBS += \
-L$$PWD/../../../Qwt-6.1.3/lib/ \
-lqwtd \
-L$$PWD/../../../Qwt-6.1.3/lib/ \
-lqwt
INCLUDEPATH += $$PWD/../../../Qwt-6.1.3/include
and to write it in the .pro-file, but for some reason the application kept looking in the old directory (and throwing errors like "cannot find someheaderfile.h"). Writing the above code in the .pri-file sovled the issue.

I have done all this before naturally, but there must have been one small thing different, because now it works.
The program crashes - but that is after the connection has been made, so I'm happy.

EDIT:
Okay, deleting:

qDebug() << connect(server_, SIGNAL(newConnection()),
this, SLOT(new_Connection()));
in:

void Listener::listen() {
if (server_!=0) qFatal("listen() called on a connection that was already initialized");
this->server_ = new QTcpServer();
server_->listen(QHostAddress::Any, port_);
qDebug() << connect(server_, SIGNAL(newConnection()),
this, SLOT(new_Connection()));
emit log(tr("Listening on port %1").arg(port_));
}
Causes the connection to no longer be made. Now I'm even more befuddled than before.

Best Regards
David

d_stranz
26th March 2018, 16:51
It's a bad idea to have any executable code in a qDebug() statement. It may not be the cause of your connect() problem, but if you need to print the result of the connect() statement, it is better to assign it to a temporary variable then output that variable's value to qDebug().

I have been burned more than once when I put executable code (i.e. code that executes to produce a side-effect, such as connect()) into an assert() or a conditional and being puzzled why the code suddenly stops working in release mode or under certain conditions, only to find out that the compiler has thrown the code away (as with assert) or optimized it away.

high_flyer
26th March 2018, 22:53
Okay, deleting:

This is in a way related to d_stranz's reply:
if you are deleting the connection you were doing in the qDebug() then the connection will not be created. (and indeed I see I didn't notice that the connected was in the qDebug() which could have beedn the cause of the connection not to have been made)
Or I don't understand what you mean with that part of your post.

DAVC
27th March 2018, 07:25
doh! Thank you so much, I was a bit tired when i wrote it.
I completely missed that it wasn't just a random:

qDebug() << "Did we get to this part of the code?"
Now it makes sense again!

I usually don't execute statements in a qDebug, this was purely because I at the time was uncertain that the connection ever got established. I just forgot to delete it again.
I will use your advice to save it in a variable and then pass it to qDebug to avoid a situation like this again, Thank you!

Best regards David

ChrisW67
27th March 2018, 09:56
Regarding the Qwt setup. Commonly you build Qwt and install it (make install) to put the resulting libs, includes etc into a configurable location (e.g. c:\Qwt-6.1.3). Then the instructions here (http://qwt.sourceforge.net/qwtinstall.html#COMPILEANDLINKAPP), with Qwt as a feature, have worked for me. Nothing but "CONFIG += qwt" needed in the PRO file for a build, but the qwt.dll needs to be in the run-time PATH of the process in order for the result to run.