QByteArray per TcpSocket verschicken

Alles rund um die Programmierung mit Qt
PeterLustig
Beiträge: 386
Registriert: 21. November 2007 20:07

Beitrag von PeterLustig »

Das meinte ich doch.. Wenn man einen QString über einen DataStream schickt, dann gibt es nur 1 Paket das diesen QString enthält. Also gibt es keinen Rest der mit einem späteren Paket kommt.
Viper2000
Beiträge: 48
Registriert: 7. Mai 2008 16:36

Beitrag von Viper2000 »

ich poste euch hier mal meinen "Client"-Code. Ser Servercode sieht dementsprechend quasi identisch aus was senden und empfangen betrifft...mein Problem ist nach wie vor, dass nicht alles ankommt was ich sende.

Viele Grüße, Viper2000

Code: Alles auswählen

#include "RF_Network_Server_ClientThread.h"
#include <QtNetwork>

RF_Network_Server_ClientThread::RF_Network_Server_ClientThread(int socketDescriptor, QObject *parent)
	: QThread(parent), socketDescriptor(socketDescriptor)
{
	connect(&gTcpSocket, SIGNAL(readyRead()),
			this, SLOT(readData()));
	connect(&gTcpSocket, SIGNAL(disconnected()),
			this, SLOT(disconnect()));
	connect(this, SIGNAL(finished()),
			this, SLOT(deleteLater()));
	
	if (!gTcpSocket.setSocketDescriptor(socketDescriptor))
	{
		///emit error(gTcpSocket.error()); //TODO
		return;
	}
	qDebug("***ClientThread constructed***");
	qDebug() << "Client Address: " << gTcpSocket.peerAddress().toString();
}


void RF_Network_Server_ClientThread::disconnect()
{
	gTcpSocket.disconnectFromHost();
	
	if (gTcpSocket.state() == QAbstractSocket::UnconnectedState || gTcpSocket.waitForDisconnected())
		qDebug("Client Disconnected");
	//Teilt der Thread-Ereignisschleife das Ende des Threads mit
	this->exit();
}

void RF_Network_Server_ClientThread::run()
{
	//In Ereignisschleife eintreten
	if (this->exec() == 0)
		qDebug() << "Thread Regulaer beendet";
}

void RF_Network_Server_ClientThread::readData()
{
	gBlockSize = 0;
	gReceivedData.clear();
	
	QDataStream in(&gTcpSocket);
	in.setVersion(QDataStream::Qt_4_3);
	
	if (gBlockSize == 0)
	{
		if(gTcpSocket.bytesAvailable() < (int)sizeof(quint32))
			return;
		
		in >> gBlockSize;
	}
	
	if (gTcpSocket.bytesAvailable() < gBlockSize)
		return;
	
	in >> gReceivedData;
	
	qDebug() << "Received size of Data from Client: " << gBlockSize;
	
	emit dataReceived(unCompressData(gReceivedData));
}

bool RF_Network_Server_ClientThread::sendData(QDomDocument& iData)
{
		QByteArray mBlock;
		QByteArray mTempArray;
		mTempArray = compressData(iData);
		
		QDataStream mOut(&mBlock, QIODevice::WriteOnly);
		mOut.setVersion(QDataStream::Qt_4_3);
		mOut << (quint32)mTempArray.size();
		mOut << mTempArray;
		
		qint64 mWritten = gTcpSocket.write(mBlock);
		gTcpSocket.flush();
		
		//msleep(60); //TODO: Pause- Größe Ermitteln

		if (mWritten == mBlock.size())
		{
			qDebug("Alle Bytes erfolgreich geschrieben");
			return true;
		}
		else if (mWritten == -1) //write returns -1 if an error occurs
		{
			qDebug() << "Ein Fehler wurde von write gemeldet: " << gTcpSocket.errorString();
			return false;
		}
		else
		{
			qDebug("Unbekannter Fehler beim Senden");
			return false;
		}
}


QDomDocument RF_Network_Server_ClientThread::unCompressData(QByteArray& iArray)
{
	QDomDocument mUncompressedData;
	QString mParseError;
	
	if (!mUncompressedData.setContent(qUncompress(iArray), &mParseError))
		qDebug() << "XML Parse not successful - Error: " << mParseError;
	else
		qDebug() << "XML Parse successful";
	
	return mUncompressedData;
}


QByteArray RF_Network_Server_ClientThread::compressData(QDomDocument& iXML)
{
	QByteArray mCompressedData;
	mCompressedData = qCompress(iXML.toByteArray());
	
	return mCompressedData;
}


RF_Network_Server_ClientThread::~RF_Network_Server_ClientThread()
{
	qDebug("***ClientThread destructed***");
}
Ich bin nicht die Signatur, ich putz hier nur :-)
Maxima
Beiträge: 27
Registriert: 23. Mai 2008 03:45

Beitrag von Maxima »

Hi viper,

füge mal den code am Ende von readData() ein

Code: Alles auswählen

void RF_Network_Server_ClientThread::readData()
{
...
 qDebug() << gTcpSocket.bytesAvailable(); 
}
vielleicht bekommst Du eine Idee worüber Sephral und ich in den vorhergehenden Posts diskutiert haben.
Viper2000
Beiträge: 48
Registriert: 7. Mai 2008 16:36

Beitrag von Viper2000 »

@Maxima&Sephral&PeterLustig&Andere: Hier mal ein Auszug vom Output meines Programmes mit deinem qDebug...
Habe 1000 QDomDocuments der gleichen Größe in ner schleife versendet. Bis zum 879ten Dokument war bytesAvailable auf 0. Dann habe ich aus Spass mal den Firefox angeworfen. Und sobald ich den Firefox gestartet hatte ging die Ausgabe von bytesAvailable hoch wie ne Rakete :) Also habe ich jetzt daraus geschlossen, dass solange die CPU nur mit dem lesen vom Netzwerk beschäftigt ist und noch etwas Luft hat, es keine Fehlenden Daten gibt. Ist die CPU jedoch mit was anderem beschäftigt, so bekomme ich etliche Fehlende Daten auf Empfängerseite. Bei diesem Durchlauf war übrigens bei 888 empfangenen Dokumenten von 1000 gesendeten Dokumenten Schluss.

Hoffe ihr könnt mir noch weitere Tips geben wie ich dieses fatale Verhalten beseitigen kann. Gruß, Viper

Code: Alles auswählen

.
.
.
.
Empfangen:  879 
21896    <<--- Dies ist die Rückgabe von QTcpSocket::bytesAvailable()
Empfangen:  880 
21896 
Empfangen:  881 
21896 
Empfangen:  882 
21896 
Empfangen:  883 
21896 
Empfangen:  884 
21896 
Empfangen:  885 
21896 
Empfangen:  886 
22134 
Empfangen:  887 
22134 
Empfangen:  888 
Ich bin nicht die Signatur, ich putz hier nur :-)
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hi Viper,

die Lösung Deines Problems wurde hier in diesem Thread schon mehrfach beschrieben.
Dir gehen keine Daten verloren, die Daten versauern lediglich in Deinem Empfangs-Buffer :-)

Bau Deine Empfänger-Routine so um, dass du auf einmal auch mehrere QByteArrays verarbeiten kannst bis der Buffer leer ist.

Du darfst Dich nicht darauf verlassen, dass du immer ein readyRead-Signal bekommst für jedes einzelne empfangene QByteArray.

Ciao,
Sephral
Viper2000
Beiträge: 48
Registriert: 7. Mai 2008 16:36

Beitrag von Viper2000 »

ok - Danke Euch, ich werde es versuchen und Berichten. Jetzt ist mir zumindest das Problem erstmal richtig klar geworden :o War bisher immer der Meinung, dass immer wenn das readyRead() Signal kommt etwas zum lesen vorhanden ist. Und wenn ich dann das weggelesen habe wieder ein readyRead() Signal kommt. Jetzt ist mir klar, dass bei nem readyRead() Signal auch mehr als ein ByteArray angekommen sein kann :)
Naja aus Fehlern lernt man eben doch dazu. :P
Ich bin nicht die Signatur, ich putz hier nur :-)
Viper2000
Beiträge: 48
Registriert: 7. Mai 2008 16:36

Beitrag von Viper2000 »

Ich habe das Problem nun Erfolgreich gelöst!

Meine Empfangsroutine:

Code: Alles auswählen

void RF_Network_Client_CommunicationThread::readData()
{	
	//Socket an den Datenstrom binden
	QDataStream in(&mTcpSocket);
	in.setVersion(QDataStream::Qt_4_3);
	
	while (mTcpSocket.bytesAvailable() >= (int)sizeof(quint32))
	{
		if (mBlockSize == 0)
		{
			in >> mBlockSize;
			//qDebug() << "BlockSize: " << mBlockSize;
			//qDebug() << "BufferSize: " << mTcpSocket.bytesAvailable();
		}
	
		//Warten bis alle Nutzdaten im internen Socketpuffer angekommen sind.
		if (mTcpSocket.bytesAvailable() < mBlockSize)
		{
			//qDebug() << "Return reached";
			return;
		}
	
		//Nutzdaten aus dem Datenstrom lesen
		in >> mReceivedData;
			
		emit dataReceived(mReceivedData);
		
		mBlockSize = 0;
		mReceivedData.clear();
	}
}
diese Routine arbeitet sauber den Puffer ab solange bis er leer ist. Wenn er leer ist wird erneut das Signal readyRead vom Socket emittiert und meine Empfangsroutine beginnt von erneut durchzurattern.
Das nur mal als kurze Rückmeldung für den Thread...könnte also als "gelöst" gekennzeichnet werden
Ich bin nicht die Signatur, ich putz hier nur :-)
Antworten