PDA

View Full Version : QTcpSocket EventLoop thread is still running?



mihau
28th February 2011, 10:41
Hi there,

I am working on a solution for let say network scanner. I need to find any host existing in a subnet. What I need is to try connect to host and if connection is established signal it somehow (signal/slot mechanism is not an issue here) to main thread. This scanner should be quite fast so i'm thinking of multiple parallel connection at the same time.
My idea is to have a collection of QTcpSockets and use it asynchronousely in main thread.
The first problem is that there is no way (as far as i know) to set connection timeout for QTcpSocket::connectToHost() for asynchronous connection (i know there is such a function waitForConnected()). I am not sure if its a good idea but I use starttimer() to simulate this timeout. When its timed out I emit signal connectionError(SocketTimeout) and then i abort connection and try to connect to next host;
Everythings works perfect exept one thing.
After first call of connectToHost() one more thread i created (is that for sockets event loop?). When I try to use more than 2 QTcpSockets this new created thread remains (is still running) after application is closed. It stays in a system for quite long time.

My question is:
How to avoid this remaining thread after application close?
Alternatively how to set timeout for asynchronous connection to host?
Maybe someone has better solution for this problem?

I'm using Qt 4.6.3 on Windows XP SP3.

Here is minimal code reproducing the problem.

Thanks a lot in advice.



#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <tsdevicediscoverysocket.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private:
Ui::MainWindow *ui;
TSDeviceDiscoverySocket sockets[2];
QHostAddress hostAddress;
bool stop;

public slots:
void onBtnStop();
void onBtnStart();
void onComplete(TSDeviceDiscoverySocket*,bool);

};

#endif // MAINWINDOW_H




#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

connect(ui->btnStart, SIGNAL(pressed()), this, SLOT(onBtnStart()));
connect(ui->btnStop, SIGNAL(pressed()), this, SLOT(onBtnStop()));

for(int i = 0; i < 2; i++)
{
connect(&sockets[i], SIGNAL(DiscoveryCompleted(TSDeviceDiscoverySocket* ,bool)), this, SLOT(onComplete(TSDeviceDiscoverySocket*,bool)));
}

stop = false;
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::onBtnStop()
{
stop = true;
}

void MainWindow::onBtnStart()
{
hostAddress.setAddress("192.168.0.1");

for(int i = 0; i < 2; i++)
{
sockets[i].lookForHostAt(hostAddress);
}
}

void MainWindow::onComplete(TSDeviceDiscoverySocket* sender, bool s)
{
if(!stop)
{
hostAddress.setAddress(hostAddress.toIPv4Address() + 1);
qDebug() << QString("Connecting to host %1").arg(hostAddress.toString());
sender->lookForHostAt(hostAddress);
}
}




#ifndef TSDEVICEDISCOVERYSOCKET_H
#define TSDEVICEDISCOVERYSOCKET_H

#include <QTcpSocket>
#include <QHostAddress>


class TSDeviceDiscoverySocket : public QTcpSocket
{
Q_OBJECT
private:
int _timeout;
int _currTimerId;

public:
explicit TSDeviceDiscoverySocket(QObject *parent = 0);
void lookForHostAt(const QHostAddress &ip);

protected:
void timerEvent(QTimerEvent *);

signals:
void DiscoveryCompleted(TSDeviceDiscoverySocket* sender, bool succeeded);
void DiscoveryStarted(const TSDeviceDiscoverySocket* sender, const QHostAddress &address);


//public slots:
private slots:
void onConnectedToHost();
void onError(QAbstractSocket::SocketError);
};

#endif // TSDEVICEDISCOVERYSOCKET_H




#include "tsdevicediscoverysocket.h"

TSDeviceDiscoverySocket::TSDeviceDiscoverySocket(Q Object *parent) :
QTcpSocket(parent)
{
connect(this, SIGNAL(connected()), this, SLOT(onConnectedToHost()));
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));

_timeout = 3000;
}


void TSDeviceDiscoverySocket::timerEvent(QTimerEvent *te)
{
Q_UNUSED(te);
onError(QAbstractSocket::SocketTimeoutError);
}

void TSDeviceDiscoverySocket::lookForHostAt(const QHostAddress &ip)
{
emit DiscoveryStarted(this, ip);
_currTimerId = startTimer(_timeout);
connectToHost(ip, 2376);
}

void TSDeviceDiscoverySocket::onConnectedToHost()
{
killTimer(_currTimerId);
emit DiscoveryCompleted(this, true);
}

void TSDeviceDiscoverySocket::onError(QAbstractSocket:: SocketError e)
{
killTimer(_currTimerId);
abort();
emit DiscoveryCompleted(this, false);
}