[solved] QT4: Datei übers Netzwerk versenden mit Q3Socket

Alles rund um die Programmierung mit Qt
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

ok, ich habe mir jetzt Qt4 open-source installiert und das programm so umgebaut, dass die daten im QByteArray erst mit ba.toBas64() kodiert und auf der server seite mit ba2 = QByteArray::fromBase64( ba1 ) dekodiert werden. jetzt liegt mein problem noch in dem prüfzeichen am ende. wie kann ich das noch mit reinbringen, dass es mitgesendet und im server danach geprüft wird?
ich habe versucht einfach per QDataStream nach dem toBase64() in das QByteArray noch ein 'µ' zu schreiben ( out << 'µ'; ), weiss aber nicht wie ich die prüfung im server jetzt implementieren soll. immer erst in ein QByteArray und dann in einen character einlesen geht ja nicht, da nur im letzten paket noch ein character dabei ist.
bitte helft mir noch einmal!

mfg,
julian
uhu01
Beiträge: 150
Registriert: 10. Juli 2005 20:46

Beitrag von uhu01 »

Hy!

Du könntest z.B. so lange einlesen, solange neue Daten vorhanden sind, und dann testen ob am Ende deine Steuerzeichen für "Datei ende" vorhanden sind, wenn nicht musst du noch weiterlesen bis die Steuerzeichen kommen.

mfg
uhu01
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

Du könntest z.B. so lange einlesen, solange neue Daten vorhanden sind
genau da war mein problem. in welcher form soll ich denn die daten verschicken? ich denke QByteArray. aber die steuerzeichen müssten dazugeschrieben werden. also so habe ich es jetzt gemacht (client.cpp):

Code: Alles auswählen

QByteArray block;
	QDataStream out( &block, QIODevice::WriteOnly );
	out.setVersion( 5 );
	out << file.readAll();
	block.toBase64();
	out << 'µ';
	socket.writeBlock( block.data(), block.size() );
im server lese ich vom stream in ein QByteArray

Code: Alles auswählen

QByteArray temp;
	in >> temp;
wie überprüfe ich nun, was da am ende drinsteht? ich muss nur wissen, wie ich das letzte zeichen im QByteArray überprüfen und (wwenn es das steuerzeichen ist) aus dem QByteArray löschen kann (sonst funktioniert fromBas64() ja nicht).
verstehst du wo mein problem liegt?

und noch eine frage:
im server, wie soll ich die einzelnen blocks speichern? eine QByteArray-element in der server-klasse und bei signal readyRead() in readClient() immer den gelesenen block dranhängen (wenn kein steuerzeichen dabei ist) ?

mfg,
julian
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Code: Alles auswählen

void readData() {
  readBlock<<readAll();
  do {
    int stop=readBlock.indexOf('µ');
    if (stop!=-1) {
      QByteArray myData=readBlock.left(stop-1);
      yourParseFkt(myData);
      readBlock.remove(0, stop+1);
    } 
  while (stop!=-1);
}
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

ok, ein stückchen code sagt mehr als 1000 worte, aber ich brauche wohl 2000.
also hier ein paar fragen:
readData() ist verbunden mit dem readyRead()-signal ?
readBlock ist ein QByteArray, aber in der 1. zeile muss es ein QDataStream sein (der in das QByteArray schreibt) ?
diese do...while schleife verstehe ich nicht. ist das desselbe wie while(){...} ?
warum steht da ungleich( != ), müsste da nicht gleich ( == ) stehen? dasselbe in der if-schleife in der while-schleife ?
yourParseFkt(): die funktion, in der alle gelesenen QByteArray-pakete aneinandergehängt werden (bzw. jeweils das gerade gelesene wird dranhegängt) ?

danke für alle antworten!

mfg,
julian
uhu01
Beiträge: 150
Registriert: 10. Juli 2005 20:46

Beitrag von uhu01 »

Hy!

Wenn ichs richtig verstanden hab dann wird der Code von upsala mehrere Blocke die hintereinander kommen zerteilen, und dann mit den jeweiligen Daten die Funktion yourParseFkt aufrufen.

Welchen Typ readBlock hat hab allerdings auch nicht mitbekommen, da QByteArray keinen operator<< hat und QDataStream kein indexOf().

readData muss dafür mit dem readyRead signal verbunden sein.

!= passt schon, du willst ja nur dann zerteilen und parsen wenn du eine gültige Datei empfangen hast.

Aneinandergehängt werden die Daten schon in dieser Funktion da, readBlock ein Member deiner Klasse sein muss, und myParseFkt erst aufgerufen wird wenn ein komplettes Files vorhanden ist.

Wenn ich richtig gedacht habe sollte das funktionieren wenn du einfach statt operator<< operator+= verwendest, allerdings nicht getestet. Dazu muss du readBlock noch zum Klassenmember, oder static machen

mfg
uhu01
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Stimmt, wenn man nicht alles testet bevor man es hierhin schreibt :)

Es muß readBlock+=readAll() heißen. Da wir hier unsere Daten von einem Netzwerk-Socket bekommen, sollten wir alle empfangenen Daten über QIODevice::readAll() einlesen können. readAll muß natürlich eine Klassenveriable vom Typ QByteArray sein (static würde ich nicht machen, könnte nach hinten losgehen...)

do...while sind C++-Grundlagen...

yourParseFkt(QByteArray) ist deine Funktion, die einen vollständigen Datenblock auswertet (Bilder, Texte...)
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

ok, ich habe das jetzt entsprechend geändert, aber wenn ich jetzt eine datei sende, wird yourParseFkt() 3 mal (4kb datei) bzw. ca. 180-200 mal (168kb datei) hintereinander aufgerufen, jedesmal kommt keine vollständige, heile datei datei da an, ich denke also dass für jeden einzelnen teil der datei, der ankommt, diese funktion aufgerufen wird.
die funktion sieht so aus:

Code: Alles auswählen

void ClientSocket::writeFile( QByteArray &block )
{
	QString fileName = Q3FileDialog::getSaveFileName();
	QFile file( fileName );
	if( !file.open( QIODevice::WriteOnly ) )
	{
		QMessageBox::warning( 0, tr( "Server -Error" ), tr( "Datei konnte nicht zum Schreiben geöffnet werden!" ) );
		return;
	}
	file.writeBlock( QByteArray::fromBase64( block ) );
	QMessageBox::information( 0, tr( "Server - Information" ), tr( "Datei wurde geschrieben!" ) );
}
entweder ich habe eure erklärungen nicht verstanden, oder es müsste eigentlich so funktionieren..tut es aber nicht.

achso ich habe das hier
readAll muß natürlich eine Klassenveriable vom Typ QByteArray
jetzt so interpretiert, dass readBlock eine Klassenvariable vom typ QByteArray sein muss, so habe ich es dann auch gemacht.
war das vielleicht schon falsch?

mfg,
julian
uhu01
Beiträge: 150
Registriert: 10. Juli 2005 20:46

Beitrag von uhu01 »

Hy!

Eigentlich sollte die parse Funktion nur aufgerufen werden wenn ein Dateiende Zeichen angekommen ist. Poste mal die Funktion die vom readyRead Signal aufgerufen wird.

mfg
uhu01
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

so das isse:

Code: Alles auswählen

void ClientSocket::readClient()
{	
	readBlock += readAll();
	int stop = -1;
	do
	{
		stop=readBlock.indexOf('µ');
		if (stop != -1)
		{
			QByteArray myData;=readBlock.left(stop-1);
			writeFile( myData );
			readBlock.remove(0, stop+1);
		}
	}while( stop != -1 );
  
	if( state() == Idle )
		deleteLater();
}
mfg,
julian
uhu01
Beiträge: 150
Registriert: 10. Juli 2005 20:46

Beitrag von uhu01 »

Hy!

Das sollte eigentlich so passen, hast du schon mal geschaut ob du wirklich ein 'µ' am Ende der Datenübertragung mitschickst?

Wenn du über den Socket nur ein File übertragen willst, dann kannst du den Socket löschen, sobald du das Ende Zeichen erhalten hast, bzw. sollte eigentlich eh die Gegenseite den Socket schließen.

Dann kannst du den mit dem Signal clientDisconnected den Socket löschen.

mfg
uhu01
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

ja, daran habe ich auch gedacht und es wird das richtige zeichen geschickt und geprüft. ich weiss nicht woran es liegt und denke auch ihr könntet das schneller/überhaupt herausfinden, deshalb habe ich den code des clients und des servers inkl. pro-file angehängt. ich wäre sehr dankbar, wenn es sich einmal jemand angucken könnte, viel code ist es ja nicht.

und ja, in diesem test möchte ich nur ein file übertragen, jedoch wird das am ende in dem fertigen programm mit dieser funktion voraussichtlich nicht so sein, dass nur ein file übertragen wird.

vielen dank im voraus!

mfg,
julian
Dateianhänge
test.zip
testprogramm
(3.46 KiB) 205-mal heruntergeladen
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Wenn du etwas mit einem QDateStream in ein QByteArray schreibst, dann werden nicht nur die reinen Daten geschrieben sondern auch Verwaltungsinformationen und die sind es, die dir Probleme bereiten. Und wenn du das ganze mit kurzen Textdateien testen würdest, würde dir das vielleicht auch auffallen.
-=Freaky=-
Beiträge: 503
Registriert: 29. Dezember 2006 22:54
Wohnort: HL

Beitrag von -=Freaky=- »

stimmt, hast recht.
aber wie soll ich die daten sonst in das QByteArray schreiben?

mfg,
julian
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

block+=file.readAll();
Antworten