Seite 1 von 1

Erledigt: Qthread tcp verbindung

Verfasst: 12. November 2010 14:49
von dazedly
Ich bin gerade dabei für meinen Server die Connections in Threads zu stecken. Jetzt habe ich das Problem, dass er readyRead irgendwie nicht anspricht. Ich bekomme keine Fehlermeldung.

Code: Alles auswählen


#include "clientconnection.h"


#include <QtNetwork>

clientConnection::clientConnection(int socketDescriptor, QObject*)
{
	this->tcpSocket = new QTcpSocket;
	this->tcpSocket->setSocketDescriptor(socketDescriptor);
	qDebug() << "Neue Verbindung von: "<<tcpSocket->peerAddress();
}

void clientConnection::run()
{
	qDebug() << "Thread gestartet"<<" Socket: "<<this->tcpSocket->socketDescriptor();

	connect(this->tcpSocket,SIGNAL(readyRead()),this,SLOT(readData()));
	qDebug() << "readyRead connected";
}

void clientConnection::readData()
{
	qDebug() << "Lese Daten";
	QByteArray tcpSockBytes = this->tcpSocket->readAll();

	if (this->data.size() == 0)
	{
		QDataStream ins(tcpSockBytes);
		ins.setVersion(QDataStream::Qt_4_7);

		quint64 size;
		ins >> size;
		this->blockSize = size;
		qDebug() << "tsize" <<size;
	}

	this->data.append(tcpSockBytes);

	int i = (int) this->blockSize + (quint64) sizeof(quint64);

	if (data.size() < i)
	{
		return;
	}
	qDebug() << "incomming data";
	this->data.clear();
	this->tcpSocket->flush();
}
Hier die Konsolenausgabe:

Code: Alles auswählen

Neue Verbindung von:   QHostAddress( "127.0.0.1" )                                                                                                                                                                                                 
Thread gestartet  Socket:  11                                                                                                                                                                                                                      
readyRead connected    
Hat jemand eine Idee?

Verfasst: 12. November 2010 16:35
von RHBaum
1. Allgemeiner Hinweis:
verwendung von Threads + Synchronen / Assynchronen Funktionalitaeten:

wenn Du selber assynchronitaet herstellen willst/musst ... solltest Du nicht auf assynchrone Funktionalitaeten anderer zurueckgreifen. Sonst kommst du recht schnell durcheinander.
Signale/Slots und generell die Signale an QSockets sind sowas. Die sind da um dir beim synchronen programmieren zu helfen, nicht beim assynchronen.

Besser, wenn selber threades:
in der run Methode synchrone Methoden laufen lassen und auf events blockieren lassen.
bool waitForConnected ( int msecs = 30000 ) am QTCPSocket ist sowas.
Die signale fuers verbinden kannst dann selber werfen !


2. QObject QThread QSocket --- wo laeuft was ?

Du erzeugst deinen QTcpSocket im CTor von clientConnection (Wer benennt klassen noch mit kleinen Anfangs-Buchstaben ? )
Das heisst Der QSocket selber wird im Thread laufen, in dem Auch clientConnection laeuft !
der wiederum lauft in dem thread, in dem er erzeugt wurde ...
(QT Thread affinititaet).
Das heisst im Klartext, alle slots ein deinem QTcpClient werden da drinne laufen ....
dein QThread, der dir ja nen thread erzeugen soll ... was er auch macht .. feuert in deinem Bsp nur die connect methode, dann verabschiedet er sich wieder ^^

Dein readData laeuft natuerlich im Thread des aufrufers ....
das kann wiederum jeder thread sein ... nur nich dein erzeugter, weil der iss da mit sicherheit schon am ende ^^

Also mit Threads, QT, Besonders QT und SignalMapping ueber threadgrenzen solltest dich ausgiebig beschaeftigen !

Warum willst ueberhaupt threaden ???
dein QTcpSocket, wenn den schoen mit assynchronen methoden von QT befeuerst, blockiert dir doch nix ...

Ciao ...

Verfasst: 12. November 2010 20:08
von solarix
RHBaum... einmal mehr verstehst du es, kurz und prägnant zu antworten :wink:

@dazedly:

Fehler 1: Dein QTcpSocket lebt im falschen Thread (wie RHBaum erklärt hat). Also: QTcpSocket erst in der run()-Methode erstellen.

Fehler 2: Dein Thread wird gleich wieder beendet (wie RHBaum erklärt hat). Also: exec() am Ende aufrufen.

Fehler 3: Wenn dann der Thread läuft: Beim Empfang hast du noch ein Denkfehler: Woher weisst du, wie viel Speicher "size" (bei "ins >> size") innerhalb des QDataStreams benötigt? Abhilfe: Trenne die Blockgrösse vom DataStream (sende also zuerst einen einzigen int64 und erst danach den QDataStream). Erstelle dann den QDataStream erst, wenn der QByteArray vollständig angekommen ist.

Hinweis: Es gibt übrigens noch eine elegantere Methode für (Q)Threading: siehe
http://labs.qt.nokia.com/2006/12/04/thr ... -headache/


hth!

Verfasst: 14. November 2010 16:13
von dazedly
Danke für die Tipps! Ich werde es gleich mal versuchen.
@Solarix: size ist ein quint64, welches ich mitsende.

Verfasst: 15. November 2010 15:28
von dazedly
Das ganze läuft jetzt fast... Nur verstehe ich nicht, warum readyRead nur vereinzelt funktioniert und das erste mal nach ausführen gar nicht.

Code: Alles auswählen


#include "clientconnection.h"


#include <QtNetwork>
#include "../libs/ronspacket.h"

clientConnection::clientConnection(int sD, QObject*)
{
	this->socketDescriptor = sD;
// 	run();
	
}

void clientConnection::run()
{
	this->tcpSocket = new QTcpSocket;
	if(!this->tcpSocket->setSocketDescriptor(this->socketDescriptor))
	{
		qDebug() << "Falscher SocketDescriptor!";
		return;
	} 
	
	
	
	qDebug() << "Neue Verbindung von: "<<tcpSocket->peerAddress();
	
	qDebug() << "Thread gestartet"<<" Socket: "<<this->tcpSocket->socketDescriptor();

	if (tcpSocket->waitForConnected())
		qDebug("Connected!");
	
	connect(this->tcpSocket,SIGNAL(readyRead()),SLOT(readData()),Qt::DirectConnection);
	connect(this->tcpSocket,SIGNAL(disconnected()),SLOT(disconnectThread()),Qt::DirectConnection);
	qDebug() << "readyRead connected"<<this->tcpSocket->state();
	
	;
	
 	QTimer timer;
 	connect(&timer, SIGNAL(timeout()), this, SLOT(update()));
 	timer.start(1000);

	exec();
}

void clientConnection::readData()
{
	qDebug() << "Lese Daten";
	QByteArray tcpSockBytes = this->tcpSocket->readAll();

	if (this->data.size() == 0)
	{
		QDataStream ins(tcpSockBytes);
		ins.setVersion(QDataStream::Qt_4_7);

		quint64 size;
		ins >> size;
		this->blockSize = size;
		qDebug() << "tsize" <<size;
	}

	this->data.append(tcpSockBytes);

	int i = (int) this->blockSize + (quint64) sizeof(quint64);

	if (data.size() < i)
	{
		return;
	}
	qDebug() << "incomming data";
	this->data.clear();
	this->tcpSocket->flush();
}

void clientConnection::disconnectThread()
{
	qDebug() << "Thread beendet!";
	this->tcpSocket->disconnectFromHost();
	this->tcpSocket->close();

	emit this->finished(this->tcpSocket->socketDescriptor(), this);
}

void clientConnection::update()
{
	qDebug() << "Verbindung steht! "<< this->socketDescriptor;
}

int clientConnection::getSocketDescriptor()
{
	return this->socketDescriptor;
}

Edit:
Warum ich Threads benutzen will:
Jeder Client muss sich in seinem eigenen Thread authentifizieren und hat in seinem Objekt (Thread) seine eigenen Umgebungsvariablen. Die Kommunikation soll bidirektional sein und nicht blockieren.

Verfasst: 16. November 2010 18:20
von dazedly
Ich habe das Problem jetzt gefunden. Es lag am QTcpServer, bzw an meiner implementierung. Ich hätte nicht das signal "newConnection" connecten dürfen, sondern "incomingConnection" implementieren sollen.
Das Problem war, dass dadurch zwei QTcpSockets offen waren und beide auf den netzwerksocket gelauscht haben. Dadurch war es mehr oder weniger Zufall, an wen die Daten gegangen sind.