1

I sticked to the tutorial about threaded qt-networking (which is here: http://doc.qt.io/qt-5/qtnetwork-threadedfortuneserver-example.html), I made some minor changes and integrated it into my main program. However incomingConnection() never gets executed, on the other hand the client is able to connect. Since I'd like to work with incomingConnection() it became obsolete to work with the SIGNAL(newConnection()) but even this isn't working.

Somebody knows what's going wrong?

Here my .h

#include <QtNetwork>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>

class WirelessNetThread: public Thread
{
    Q_OBJECT

public:
    WirelessNetThread(int socketDescriptor, QObject * parent);

    void run() Q_DECL_OVERRIDE;

signals:
    void error(QTcpSocket::SocketError socketError);

private:
    int socketDescriptor;
    QString text;
};

class WirelessNet : public QTcpServer
{
    Q_OBJECT

public:
    WirelessNet(QObject *parent = 0);

protected:
    void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;

};

And the .cpp

WirelessNetThread::WirelessNetThread(int socketDescriptor, QObject *parent):QThread(parent), socketDescriptor(socketDescriptor)
{
}

void WirelessNetThread::run()
{
    QTcpSocket tcpSocket;
    if ( !tcpSocket.setSocketDescriptor(socketDescriptor))
    {
        emit error(tcpSocket.error());
        return;
    }

    tcpSocket.disconnectFromHost();
    tcpSocket.waitForDisconnected();
}

WirelessNet::WirelessNet(QObject *parent): QTcpServer(0)
{
    listen(QHostAddress::Any, 5220);
    printf("is listening %d\n", this->isListening());
}

void WirelessNet::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "incomming \n";
    printf("incomming \n");
    WirelessNetThread *thread = new WirelessNetThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

here the excerpt out of my main program, where it is initiated (by the way it doesn't matter if I leave out moveToThread():

WirelessNet *wifi = new WirelessNet(this->parent());
wifi->moveToThread(this->thread());

Even this has no influence if I add these lines after the initalization of wifi:

wifi = new WirelessNet(this->parent());
QEventLoop testLoop;
testLoop.exec();

In other words "incomming" is never printed out, and so I'm not able to work on. Has anyone an idea, this is pretty much 1:1 the code from the tutorial that's what confuses me.

user3085931
  • 1,757
  • 4
  • 29
  • 55
  • 1
    This code is from a tutorial?... do you have a link to it? - its either very old, or very poorly written (Qt-wise). I struggle to see how "incomingConnection()" is ever called - is there a signal connected to it? But before you go too far into this... there is a lot of messing around with inheriting threads and starting event loops.... all not required and makes it very messy to follow and maintain. I literally just posted an answer regarding threads here: http://stackoverflow.com/questions/36201769/threads-event-loop-in-the-qt-application/36208479#36208479 - look at the usage of QThread – code_fodder Mar 24 '16 at 19:44
  • .. for you its 4 lines of code extra to your standard Qt class to put it into a thread. Then all of the code in your WirelessNet class can focus on "wireless network stuff" and no thread nonsense : ). I could post up an answer with how I would implement what you are doing... but I am still missing how `incomingConnection()` is called.... – code_fodder Mar 24 '16 at 19:46
  • @code_fodder the link to the tutorial is mentioned in the very first line. I had/have the same struggle about `incomingConnection()`. AFAIU this function is an overridden function (i.e. a virtual function), that has similar mechanisms as an overriden `run()` function if you inherit a class from `QThread`. Unfortunately I haven't had the time to have a closer look – user3085931 Mar 30 '16 at 06:36
  • @code_fodder I tried your approach with the code mentioned in the other topic. I get the Signal/Slot response from one class to another, however the main problem hasn't changed either. Still no reaction on `incomingConnection()` nor on `SIGNAL(newConnection())` – user3085931 Mar 30 '16 at 07:25
  • Ah, its a TcpServer over-ride function, got it. The docs say that this function (when not overridden) will emit the newConnection() signal. I know you said you tried to catch this signal, but did you try to do this after removing your own override function incomingConnection()? (i.e. using something like `connect(myTcpObj, SIGNAL(newConnection()), this (), SLOT(someSlotWithDebugInIt()));`, I only ask in case there is something wrong with your incomingConnection (can't see what) to check if the base is working at all. – code_fodder Mar 30 '16 at 09:23
  • @code_fodder yes I tried both methods solely. Well one thing I'd like to mention: if I run client and server as simple programs, it's running. Just only when I integrate the server into my main application and I don't know why. I suspect a malfunctioning `QEventLoop` for this behavior, but if it was so it shouldn't be there anymore after making and running another instance of it (i.e.: as mentioned in the top post `QEventLoop testLoop; testLoop.exec();`) – user3085931 Mar 30 '16 at 09:57
  • well... this is the thing with running your own event loop... you really don't need to be doing that I feel. If you create a QThread object (which runs its own event loop when you call myThread->start()) and then with your original TcpServer object use moveToThread() (before you start the thread) and connect - kind of as described in the link I sent - then you should only have to worry about TcpServer stuff and not event loops or thread inheritance, etc... NOTE the order is important, once you start the thread you should only communicate to your object via slots/signals. – code_fodder Mar 30 '16 at 10:38
  • ... I think it would become very simple code... looking at your code in your main program, you would create your `wifi` object, move it into a new thread, connect it up and then run it. I don't think you would need `WirelessNetThread` at all... I am not sure what you are doing with the QTcpSocket though :o ... I could write a short example for your setup if you want, but I would have to do it as an answer since can't easily write code in this comment box :( – code_fodder Mar 30 '16 at 10:47
  • @code_fodder I think once I already implemented like you just mentioned, but if you don't mind please upload the code and I can double check if we mean the same. You are right I don't see the necessity of `WirelessNetThread` I just sticked to the tutorial code to avoid as many errors as possible. What is inside `run()`, with `QTcpSocket` shouldn't be a thing, since it will be changed anyway. The actual problem is I never even get to this point. – user3085931 Mar 30 '16 at 10:53
  • Ok, I'll stick the code up as I think it should be... btw run() is overload of QThread::run() not QTcpSocket : ) – code_fodder Mar 30 '16 at 10:59

1 Answers1

2

In your main code:

WirelessNet *wifi = new WirelessNet(0); // 0 = assign no parent
QThread *wifiThread = new QThread;
wifi->moveToThread(wifiThread);
QObject::connect(wifiThread, SIGNAL(started()), wifi, SLOT(startWifi()));
// start() will start its own event loop, it will emit started(), therefore startWifi() slot will be called.
wifiThread->start();

Then your WirelessNet class header:

class WirelessNet : public QTcpServer
{
    Q_OBJECT

public:
    WirelessNet(QObject *parent = 0);

protected:
    void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;

public slots:
    void startWifi();
};

Then your WirelessNet class body:

WirelessNet::WirelessNet(QObject *parent) : 
    QTcpServer(parent)
{
    // Do nothing much here because we want to initialise new stuff in our thread.
    // When this function runs we have not moved this to the new thread - or even started it.
}

void WirelessNet::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "incomming \n";
    printf("incomming \n");
    WirelessNetThread *thread = new WirelessNetThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

// Called when the thread has started
void WirelessNet::startWifi()
{
    // Anything done here is now safely within out new thread.
    listen(QHostAddress::Any, 5220);
    printf("is listening %d\n", this->isListening());
}

note this is example code, I wrote it directly into stack overflow it has not been compiled, so there are probably some errors :) There are some key points, that I have commented, where you may have gone wrong in your original attempt.

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • I honestly don't get this behavior. Now the body of `WirelessNet()` is empty and `startWifi()` is as mentioned in your code. Before it was the other way round: `startWifi()` was practically empty and the constructor `WirelessNet()` was listening(). So it's working now and I'm happy with that, but would you mind explaining me the difference ? – user3085931 Mar 30 '16 at 11:33
  • 1
    The thing here is (I tried to explain in the comments, but poorly) when you create your wifi object, the c'tor is called (i.e. WirelessNet::WirelessNet()). Anything you create here will be created in the thread that created wifi - i.e. the main thread. So I removed your listen call. Then after you do wifi.moveToThread(...); and then start the thread (thread->start()) your object wifi now lives in the new thread (and thread also becomes its parent). Also, because we connected QThread::started() signal to WirelessNet::startWifi() slot, when the thread starts it emits the signal and ... – code_fodder Mar 30 '16 at 11:44
  • 1
    ... startWifi() is executed. Note, anything run in this function/slot will now be running in the new thread. So I moved your listen() function into here. There where other minor issues with your original setup (like assigning a parent) have another look at my comments, I only commented where there is something interesting going on. I can't say 100% why moving listen within the thread works because I don't know what listen does.... but if it creates any objects they would be in the wrong place (thread)! – code_fodder Mar 30 '16 at 11:46
  • 1
    Hopefully, you find this code much simpler to understand then inheriting and running event loops and things! One more thing to note: QThread is not a thread, it is a thread controller object (it starts a thread in the background for you, and the event loop too). – code_fodder Mar 30 '16 at 11:48
  • many thanks for your patience and precise answers, sometimes you're looking for a `;` and then there are times where things like this happen, you read it a thousand times and still don't suspect a thing ;) – user3085931 Mar 30 '16 at 11:51
  • I wrestled with qt qthreads for an quite a while, they are just a bit different to posix (or other systems) in the way they are used, so I know them quite well now... but also the pitfalls, because they are not very obvious. Glad its working : ) – code_fodder Mar 30 '16 at 14:46
  • Wrestling isn't even dark enough to express these circumstances ;) have a fine day – user3085931 Mar 31 '16 at 06:18