Seite 1 von 2

QTcpSocket auf dem Heap anlegen?

Verfasst: 21. Mai 2008 17:56
von Viper2000
Hallo,

habe ein Programm geschrieben was bei jeder eingehenden Clientverbindung eines QServerSocket einen Thread erzeugt, der dann die Clientkommunikation abwickelt.
In diesem "ClientThread" hab ich jetzt zwei möglichkeiten probiert. Einmal den Socket mit

QTcpsocket tcpSocket;

und einmal mit

QTcpsocket *tcpSocket; und später tcpSocket = new QTcpSocket();

erzeugt.
Also im zweiten Fall dynamisch auf dem Heap.

Hänge auch nochmal beide CPP Dateien hier an. Mir sind die Vor- und Nachteile dieser zwei Möglichkeiten noch nicht so wirklich klar. Vielleicht kann jemand was dazu sagen.

Fall 1: Socket mit "QTcpSocket tcpSocket" in der Header.

Code: Alles auswählen

//FILE: clientThread.cpp
#include "clientThread.h"
#include <QtNetwork>

ClientThread::ClientThread(int socketDescriptor, QObject *parent)
	: QThread(parent), socketDescriptor(socketDescriptor)
{
	qDebug("***ClientThread constructed***");
	connect(&tcpSocket, SIGNAL( readyRead() ), this, SLOT( readFortune() ) );
	connect(&tcpSocket, SIGNAL( disconnected() ), this, SLOT( setDisconnect() ) );
	connect(this, SIGNAL( finished() ), this, SLOT( deleteLater() ) );
	
	if( !tcpSocket.setSocketDescriptor( socketDescriptor ) )
	{
		emit error(tcpSocket.error());
		return;
	}
	//sendWelcome();

	qDebug() << "Client Address: " << tcpSocket.peerAddress().toString();
}
Fall 2: Socket mit "QTcpSocket *tcpSocket" in der Header.

Code: Alles auswählen

//FILE: clientThread.cpp
#include "clientThread.h"
#include <QtNetwork>

ClientThread::ClientThread(int socketDescriptor, QObject *parent)
	: QThread(parent), socketDescriptor(socketDescriptor)
{
       tcpSocket = new QTcpSocket();
	qDebug("***ClientThread constructed***");
	connect(tcpSocket, SIGNAL( readyRead() ), this, SLOT( readFortune() ) );
	connect(tcpSocket, SIGNAL( disconnected() ), this, SLOT( setDisconnect() ) );
	connect(this, SIGNAL( finished() ), this, SLOT( deleteLater() ) );
	
	if( !tcpSocket->setSocketDescriptor( socketDescriptor ) )
	{
		emit error(tcpSocket->error());
		return;
	}
	//sendWelcome();

	qDebug() << "Client Address: " << tcpSocket->peerAddress().toString();
}

Verfasst: 21. Mai 2008 18:27
von Christian81
In beiden Fällen liegt es auf dem Heap da Du ClientThread bestimmt mit new() erzeugst.

Verfasst: 21. Mai 2008 18:35
von Viper2000
ich wusste nicht, dass wenn man ne Klasse(hier Thread) mit new() Erzeugt auch alles interne der Klasse dann auf dem Heap liegt. Klingt aber logich ;)

Soll das also heißen, dass es gehoppt wie gesprungen ist welche Methode ich anwende!?

Verfasst: 21. Mai 2008 18:48
von Christian81
Mehr oder weniger ja - kommt eben drauf an ob Du am Ende ein delete machen willst oder nicht. Aber selbst das erübrigt sich ja meistens wenn man einen parent mit angibt. Und da Qt-Klassen intern sowieso alles in einer privaten Klasse anlegen die per new() erzeugt wird liegt gar nicht so viel auf dem Stack wie man annimmt.

Verfasst: 21. Mai 2008 19:06
von Viper2000
ok, habe grad mal in das "Threaded Fortune Server Example" in der Qt4 Dokumentation geschaut. Dort nutzen sie den Heap nicht. Lediglich der einmalig erzeugte QTcpServer wird auf dem Heap angelegt.

Allerdings wird dort jeder Thread sofort wieder beendet und bekommt keine eigene Eventloop wie bei mir im Projekt. Meine Threads laufen solange bis ein Client sich wieder Disconnected. Dann wird der Thread deleted.

Verfasst: 23. Mai 2008 11:16
von Maxima
Ich habe bei mir eine Klasse generiert, die die TcpSockets sammelt und es funktioniert ganz gut, deswegen die Frage:
Ist es in Deiner Anwendung nötig für jeden TcpSocket einen eigenen thread (mit eigener event-loop) anzulegen? Wo sind die Vorteile?

Verfasst: 23. Mai 2008 11:54
von Viper2000
Hi, ja es war eigentlich so gedacht, dass für jede Clientverbindung ein eigener Thread gestartet wird.

Ich dachte das wäre die Standard Vorgehensweise für jeden cleint nen Thread zu eröffnen...

Kannste mir deine Thread-Sammelklasse mal zeigen!?

Verfasst: 23. Mai 2008 12:13
von Maxima

Code: Alles auswählen

class MyConnection : public QObject
{
...
signals:
...
slots:
...
private:
QTcpSocket * tcp;
...
};

QList<MyConnection*> socketListe;

die class hat slots und signals für die Außen-Welt
Weis nicht ob das hilfreich für Dich ist...
(BTW: ist auch aus dem fortuneserver entstanden, der ja einfach einen TcpSocket mit connect-slot-signals verknüpft und bei disconnect dann löscht ohne eine Liste zu benutzen)

Bis jetzt reicht es für mich, aber es ist spannend zu wissen, was hier (TcpSockets) der Vorteil eines Threads ist/sein könnte.

Verfasst: 23. Mai 2008 12:16
von Christian81
QList<MyConnection> socketListe;
Wirklich? Kann nämlich nicht gehen :)

Verfasst: 23. Mai 2008 12:21
von Maxima
danke, korrigiert :D

Verfasst: 23. Mai 2008 12:46
von keeney
Wenn der Server viele Clients handlen soll, dann wuerd ich dir empfehlen, einen Threadpool zu verwenden, sonst steigt dir das Betriebssystem irgendwann auf's Dach. Und bedenke, dass jeder erzeugte Thread Speicher verbraucht, und das nicht wenig.

Verfasst: 23. Mai 2008 14:37
von Viper2000
Wir reden hier in meinem Fall in der Größenordnung von 5 oder 6 Clients. Also 5 oder 6 Threads...

Ich dachte mir bisher, da ich auf das readyRead() Signal einer jeden Verbindung reagieren will, dass ich für jede Verbindung einen eigenen Thread kreiere und in jedem Thread eine eigene EventLoop laufen lasse.

In ersten Tests funktioniert soweit auch alles.

Jetzt habt ihr mich aber verunsichert und ich weiß nichtmehr was ich machen soll - dafür bin ich zu unerfahren auf dem Gebiet. Komme eher aus der Mikrocontroller sparte :lol: :lol: :lol:

Verfasst: 23. Mai 2008 15:15
von Christian81
Für fünf bis 6 Threads ist das allemal ok so wie du es gemacht hast. Zumal Du ja die threads auch recht schnell wieder löschst.

Verfasst: 23. Mai 2008 15:49
von Maxima
Viper2000 hat geschrieben:Jetzt habt ihr mich aber verunsichert und ich weiß nichtmehr was ich machen soll - dafür bin ich zu unerfahren auf dem Gebiet. Komme eher aus der Mikrocontroller sparte :lol: :lol: :lol:
Sorry, die Frage sollte Dich nicht verunsichern! :)
Ich dachte/denke, daß alle etwas lernen können, wenn wir sowas diskutiert.

Beide Ansätze funktionieren ja ganz gut, die Frage war/ist wo die Grenzen der einzelnen Methoden wären.
Eine gute Einsicht ist ja schon mal, daß threads mehr Speicher verbrauchen.

Das (die limits) können wir ja hier ergänzen, wenn wir sie erreichen sollten.

:)

Verfasst: 23. Mai 2008 19:46
von Viper2000
Ja klar, ein Forum ist ja zum Diskutieren gedacht :)

Also meine Methode:
Bei jedem Client der connected einen eigenen Thread erzeugen und in diesem Thread eine Eventloop mit "exec" starten und auf Signale wie z.B. "readyRead()" reagieren. Der Thread bleibt solange mit seiner Eventloop bestehen bis der Client sich vom Server disconnected!
Deine Methode:
Bei jeder eingehenden Clientverbindung eine Klasse auf dem Heap mit new instanzieren, welche die Funktionalität der Kommunikation enthält. Die Objekte der Klassen dann in eine QList packen. Auf Threads wird vollkommen vezichtet.
So ist das doch richtig Maxima oder...

Auch alle anderen mit viel Erfahrung sind gefragt welche Vorgehensweise sie bevorzugen würden.