PDA

View Full Version : Do i have to inherit from QTcpServer?



p.kreker
16th June 2011, 14:09
Hi,

I’m trying to create a threaded server and in every example I saw someone creates a server by inheriting from QTcpServer. So I wonder, do I have to? I mean, you inherit only if you want to extend the class.

Here is the class:
myserver.h

#ifndef MYSERVER_H
#define MYSERVER_H

#include <QObject>
#include <QtNetwork/QTcpServer>
#include <QtConcurrentRun>
#include <QFuture>
#include "myclienthandle.h"

class MyServer : public QObject
{
Q_OBJECT
public:
explicit MyServer(QObject *parent = 0, const QString &ip = "Any", int port = 0);
explicit MyServer(const MyServer &server);
~MyServer();
QString IP() const;
void setIP(const QString &ip);
int Port() const;
void setPort(int port);
bool isAlive() const;


private:
QTcpServer *m_qtcpserListener;
QFuture<void> m_qftrRun;
QString *m_qstrIP;
int m_iPort;
int m_iClientID;
bool m_bRun;

void run();

signals:
void newConnection(MyClientHandle *clientHandle);

public slots:
void start();
void stop();
};

inline QString MyServer::IP() const
{
return *m_qstrIP;
}

inline void MyServer::setIP(const QString &ip)
{
m_qstrIP = new QString(ip);
}

inline int MyServer::Port() const
{
return m_iPort;
}

inline void MyServer::setPort(int port)
{
m_iPort = port;
}

inline bool MyServer::isAlive() const
{
return m_bRun;
}

#endif // MYSERVER_H

myserver.cpp

#include "myserver.h"

MyServer::MyServer(QObject *parent, const QString &ip, int port) :
QObject(parent), m_iClientID(0), m_bRun(false)
{
setIP(ip);
setPort(port);
}

MyServer::MyServer(const MyServer &server)
{
MyServer(server.parent(), server.IP(), server.Port());
}

MyServer::~MyServer()
{
stop();
}

void MyServer::run()
{
m_qtcpserListener = new QTcpServer(this);

if (!m_qtcpserListener->listen(QHostAddress(IP()), Port()))
{
return;
}

while (m_bRun)
{
QTcpSocket *qtcpsoNextPending = m_qtcpserListener->nextPendingConnection();
if(qtcpsoNextPending != 0)
{
emit newConnection(new MyClientHandle(qtcpsoNextPending));
}
}
}

void MyServer::start()
{
m_bRun = true;
m_qftrRun = QtConcurrent::run(this, &MyServer::run);
}

void MyServer::stop()
{
m_bRun = false;
if (m_qtcpserListener->isListening())
{
m_qtcpserListener->close();
}
}

Greats p.kreker

Santosh Reddy
17th June 2011, 01:54
You should be able to implement with out inheriting QTcpServer, are you having any problem with it?

Just some thought, you are creating QTcpServer in the context on new thread, so the parent cannot be "this" as it was created in the main thread context.

deyili
17th June 2011, 03:38
inheriting is the strongest coupling, so don't use it if you has another option.

p.kreker
27th June 2011, 23:38
Okay... I had doubts whether I'm doing it right. I think the Qt documentation confuses more than it helps. :D

I've moved the QTcpServer in an extra thread... This way was easier.

Here's the final version of the MyServer class:

myserver.h


#ifndef MYSERVER_H
#define MYSERVER_H

#include <QObject>
#include <QtNetwork/QTcpServer>
#include "myclienthandle.h"

class MyServer : public QObject
{
Q_OBJECT
public:
explicit MyServer(const QHostAddress &address = QHostAddress::Any, unsigned short port = 0, QObject *parent = 0);
explicit MyServer(const MyServer &server);
~MyServer();
QHostAddress Address() const;
void setAddress(const QHostAddress &address);
unsigned short Port() const;
void setPort(unsigned short port);
bool isRunning() const;


private:
QTcpServer *m_qtcpserListener;
QHostAddress *m_qhaddAddress;
QThread *m_qthServer;
unsigned short m_iPort;
bool m_bRunning;

void init(const QHostAddress &address, unsigned short port);

signals:
void clientConnected(int socketDescriptor);
void startError();

public slots:
void start();
void stop();
void m_qtcpserListener_newConnection();
};

inline QHostAddress MyServer::Address() const
{
return *m_qhaddAddress;
}

inline void MyServer::setAddress(const QHostAddress &address)
{
m_qhaddAddress = new QHostAddress(address);
}

inline unsigned short MyServer::Port() const
{
return m_iPort;
}

inline void MyServer::setPort(unsigned short port)
{
m_iPort = port;
}

inline bool MyServer::isRunning() const
{
return m_bRunning;
}

inline void MyServer::m_qtcpserListener_newConnection()
{
emit clientConnected(m_qtcpserListener->nextPendingConnection()->socketDescriptor());
}

#endif // MYSERVER_H


myserver.cpp


#include "myserver.h"

MyServer::MyServer(const QHostAddress &address, unsigned short port, QObject *parent) :
QObject(parent), m_bRunning(false)
{
init(address, port);
}

MyServer::MyServer(const MyServer &server) :
QObject(server.parent()), m_bRunning(false)
{
init(server.Address(), server.Port());
}

MyServer::~MyServer()
{
stop();
delete m_qtcpserListener;
delete m_qthServer;
}

void MyServer::init(const QHostAddress &address, unsigned short port)
{
m_qtcpserListener = new QTcpServer;
m_qthServer = new QThread(this);
setAddress(address);
setPort(port);

connect(m_qtcpserListener, SIGNAL(newConnection()),
this, SLOT(m_qtcpserListener_newConnection()),
Qt::DirectConnection);

m_qtcpserListener->moveToThread(m_qthServer);
}

void MyServer::start()
{
m_qtcpserListener->thread()->start();
m_qtcpserListener->thread()->setObjectName(tr("Listeners Thread"));
if (!m_qtcpserListener->listen(Address(), Port()))
{
stop();
emit startError();
} else {
m_bRunning = true;
}
}

void MyServer::stop()
{
m_bRunning = false;
if (m_qtcpserListener->isListening())
{
m_qtcpserListener->close();
}
m_qtcpserListener->thread()->quit();
m_qtcpserListener->thread()->wait();
}

Santosh Reddy
28th June 2011, 00:56
This looks ok, is this working for you?

p.kreker
28th June 2011, 09:31
Yes it works fine :)

Edit 1:
But I get this debug message:


QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpServer(0x1e3f6c8), parent's thread is QThread(0x1e3f9b0), current thread is QThread(0x1e37a40)


At this command in the listen methode of m_qtcpserListener:


bool QTcpServer::listen(const QHostAddress &address, quint16 port)
{
...
d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstrac tSocket::TcpSocket, proxy, this);
...
}


Why is the current thread in this methode different then the m_qtcpserListener thread? I mean, I've moved the m_qtcpserListener to an other thread, so the methodes should be executed in this thread or am I wrong?

Santosh Reddy
28th June 2011, 11:07
QTcpServer::listen() is called from MyServer::start(), MyServer::start() runs in the context of the first / main thread, and you have already moved QTcpServer to new thread:eek:

So move QTcpServer to new thread after QTcpServer::listen(), may be as last statement in MyServer::start()

p.kreker
28th June 2011, 11:25
Learing never stops :D

Now the server works perfect :)