Seite 1 von 3

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

Verfasst: 29. Dezember 2006 23:20
von -=Freaky=-
hi, da ich neu hier im forum bin güße ich erstmal alle hier.
so, jetzt zu meinem problem:
ich versuche (für ein kleines chatprogramm), eine datei per QSocket über das netzwerk zu verschicken. bevor ich lange erkläre wie ichs angestellt habe, hier der code dazu (nur ein kleines testprogramm):
client.cpp:

Code: Alles auswählen

#include "client.h"

cl::cl( QWidget *parent, const char *name)
	:	QPushButton( tr("Beenden"), parent, name )
{
	socket.connectToHost( "localhost", 1492 );
	blocksize = 0;
	
	QString fileName = QFileDialog::getOpenFileName();
	QFile file( fileName );
	if( !file.open( IO_ReadOnly ) )
	{
		QMessageBox::warning( this, tr( "Client - Error" ), tr( "Datei %1 konnte nicht zum Lesen geöffnet werden!" ).arg( file.name() ) );
		return;
	}
	QByteArray block;
	QDataStream out( block, IO_WriteOnly );
	out.setVersion( 5 );
	out << (Q_UINT16) 0 << file.readAll();
	out.device()->at( 0 );
	out << (Q_UINT16) ( block.size() - sizeof( Q_UINT16 ) );
	socket.writeBlock( block.data(), block.size() );
}
server.cpp:

Code: Alles auswählen

#include "server.h"

sv::sv( QWidget *parent, const char *name )
	:	QServerSocket( 1492, 1, parent, name )
{
}

void sv::newConnection( int socketId )
{
	ClientSocket *socket = new ClientSocket( this );
	socket->setSocket( socketId );
}

ClientSocket::ClientSocket( QObject *parent, const char *name )
	:	QSocket( parent, name )
{
	connect( this, SIGNAL( readyRead() ),
				this, SLOT( readClient() ) );
	connect( this, SIGNAL( connectionClosed() ),
				this, SLOT( deleteLater() ) );
	connect( this, SIGNAL( delayedCloseFinished() ),
				this, SLOT( deleteLater() ) );
				
	blocksize = 0;
}

void ClientSocket::readClient()
{	
	QDataStream in( this );
	in.setVersion( 5 );
	if( blocksize == 0 )
	{
		if( bytesAvailable() < sizeof( Q_UINT16) )
		{
			QMessageBox::information( 0, tr( "Server - Error" ), tr( "bytesAvailable() < sizeof( Q_UINT16)" ) );
			return;
		}
		in >> blocksize;
		if( bytesAvailable() < blocksize )
		{
			QMessageBox::warning( 0, tr( "Server - Error" ), tr( "bytesAvailable() < blocksize" ) );
                        return;
		}
	}
	QByteArray block;
	in >> block;
	
	QString fileName = QFileDialog::getSaveFileName();
	QFile file( fileName );
	if( !file.open( IO_WriteOnly ) )
	{
		QMessageBox::warning( 0, tr( "Server - Error" ), tr( "Datei %1 konnte nicht zum Schreiben geöffnet werden!" ).arg( file.name() ) );
		return;
	}
	file.writeBlock( block );
	QMessageBox::information( 0, tr( "Server -Information" ), tr( "Schreiben von Datei\n%1\nbeendet." ).arg( file.name() ) );
	
	close();
	if( state() == Idle )
		deleteLater();
	
	blocksize = 0;
}
mein problem besteht nun darin, dass nur wenige kb gesendet werden (oder ankommen). von einem bild mit 1280x1024 pixeln, 168kb, kommen nur ein paar zeilen an (der rest des bildes (90-95%) ist grau) und ich bekomme die meldung "bytesAvailable() < blocksize". dasselbe bild auf 50x40 skaliert, 4kb, kommt allerdings komplett und ohne fehler an.

ich vermute den fehler beim einlesen der datei in das QByteArray, also entweder beim QDataStream, der die daten immernoch ins QByteArray schreibt wenn der block verschickt wird, oder beim "file.readAll()", das immernoch die daten einliest, wenn der block schon verschickt wird.

das sind aber wie gesagt nur vermutungen, und ich bin noch neu bei QT und lerne erst seit einem jahr überhaupt C++. vielleicht zur information noch: ich schreibe das programm ausschließlich in QT3, zur übung, da das buch womit ich mich in QT einarbeite auch nur zu QT3 ist.

danke im voraus für jede hilfe!

mfg,
julian

Verfasst: 29. Dezember 2006 23:36
von upsala
Ab einer bestimmten Blockgröße werden Pakete im Netz fragmentiert. Das readyRead-Signal kommt wenn ein Block empfangen wurde. Du mußt die einzelnen Blöcke erst komplett empfangen und zusammensetzen und dann kannst du damit weiterarbeiten...

Verfasst: 29. Dezember 2006 23:41
von -=Freaky=-
ok danke schonmal,
aber wie bekomme ich heraus, wann der letzte block empfangen wurde bzw. dass noch welche ausstehen? also wie weiss ich, dass 2 pakete, die nacheinander kommen, zusammengehören? wie kann ich das realisieren?

mfg,
julian

Verfasst: 29. Dezember 2006 23:45
von upsala
connectionClosed() zeigt dir das Ende und alle Blöcke einer Verbindung sollten zusammengehören.

Verfasst: 29. Dezember 2006 23:54
von -=Freaky=-
stimmt zwar, aber nachher im programm sollen die chat-nachrichten auch darüber gesendet werden und zwischendurch die dateien. meinst du ich sollte dafür einen eigen QSocket benutzen?

mfg,
julian

Verfasst: 29. Dezember 2006 23:57
von uhu01
Hy!

Du könntest z.B. deine Daten Base64 Codieren, und bei Dateiende ein Steuerzeichen schicken...

mfg
uhu01

Verfasst: 30. Dezember 2006 01:11
von -=Freaky=-
ok danke für den tipp, aber ich bin wie gesagt noch nicht lange dabei. habe mich kurz bei wikipedia informiert über Base64 und es im ansatz verstanden, aber keine ahnung wie ich das umsetzen soll.
wäre nett, wenn du mir das kurz erklären könntest (auch das mit dem steuerzeichen).
also sehe ich das richtig: ich nehme mir z.B. diesen en-/decoder http://www.adp-gmbh.ch/cpp/common/base64.html und kodiere die daten aus der datei mit base64_encode und häng ein erkennungszeichen hintendran. wenns rauskommt (server-seite) guck ich nach dem erkennungszeichen, wenn es gefunden wird, nehme ich es raus und alles bis einschließlich diesem paket wird in einem string aneinandergehängt und mit base64_decode dekodiert und in eine datei geschrieben ?

würde das überhaupt funktionieren oder müsste ich trotzdem noch ein zweites QSocket-objekt da haben, um chatnachrichten und dateien getrennt zu verschicken?

mfg,
julian

Verfasst: 30. Dezember 2006 01:16
von uhu01
Hy!

Ich denke über nen eigenen Socket ist es sicher einfacher zu machen, allerdings ists auch mit einem möglich, sehe da aber keinen Vorteil, wenn du dein Programm nur im LAN benutzen möchtest.

Und ja, das mit dem Base64 hatte ich so gemeint, allerdings hat Qt das schon eingebaut ;-) brauchst du keine externe Library nehmen...
z.B. hat QByteArray die Funktionen toBase64 und fromBase64

mfg
uhu01

Verfasst: 30. Dezember 2006 01:56
von -=Freaky=-
naja, mal sehen ob ich das ding nur im lan benutzen will, wenn ich es einigermaßen hinbekomme, könnte es schon probeweise mal als internet-messenger eingesetzt werden (für mich und meine leute aus der klasse, genügend hausaufgaben zum umherschicken hätten wir (reiner testzweck!!!) :D), da wär dann nur das problem mit den benutzerkonten und wenn ich das eingebaut habe bräuchte ich nen server, was wieder stromkosten für die eltern wären. aber egal, das ist was anderes...

erstmal vielen dank für die hilfe! ich werde das ganze morgen mal ausprobieren und dann rückmeldung erstatten.

mfg,
julian

Verfasst: 30. Dezember 2006 02:30
von uhu01
Hy!

Hast du ja noch einiges vor...
Bitte ändere doch den Titel des Thread auf [solved]...

mfg
uhu01

Verfasst: 30. Dezember 2006 11:07
von -=Freaky=-
ok, kann es sein, dass diese funktionen ab QT4 dabei sind? ich arbeite wie gesagt nur mit QT3, der QT3-assistant gibt mir auch keine funde für toBase64 und fromBase64. ich habe es jetzt mit dem en-/decoder aus dem link versucht, aber kläglich versagt. ich habe jetzt alles mit QStrings gemacht, weil diese funktionen nur strings ausgeben. wär nett wenn du mir nochmal helfen könntest. danke!

oder gibt es eventuell noch andere wege als die base64-kodierung ?

mfg,
julian

Verfasst: 30. Dezember 2006 13:15
von upsala
Ja, diese Funktionen sind Qt4-Funktionen (was spricht eigentlich dagegen auf Qt4 umzusteigen?)

Verfasst: 30. Dezember 2006 13:26
von uhu01
Hy!

Entschuldige ich hatte ganz übersehen das ich die falsche Doku offen hatte.

Die Funktionen aus deinem Link arbeiten allerdings mit std::strings, d.h. du musst deine QStrings zuerst ein einen std::string Umwandeln, und dann deine decode-encode Funktionen aufrufen, oder du schreibst die Funktionen um, das sollte nicht das Problem sein...

Wenn du mehrere Sockets verwendest, ist es sicher kein Problem die Base64 Codierung wegzulassen, kann allerdings sehr hilfreich sein, da du dir leichter tut die Information in deinen Pakete unterzubringen, du weist ja das du nur Buchstaben und bestimmte Sonderzeichen haben wirst. Ist vor allem bei Files ein Vorteil, wenn du in deinen Paketen noch irgendwelche Kontrollinformationen mitschicken willst.

mfg
uhu01

Verfasst: 30. Dezember 2006 13:31
von -=Freaky=-
upsala hat geschrieben:was spricht eigentlich dagegen auf Qt4 umzusteigen?
ich lerne gerade erst mit Qt umzugehen und habe mir dazu letztes jahr auf der cebit ein buch zu Qt3 ("GUI-Programmierung mit Qt3" von Jasmin Blanchette und Mark Summerfield, Addison-Wesley-Verlag) gekauft, wo ich mich auch durcharbeite und das chatprogramm sollte mal eine übung zur Qt-programmierung sein.

meinst du, es wäre sinnvoller erst das buch durchzuarbeiten und Qt3 einigermaßen zu beherrschen oder gleich auf Qt4 umzusteigen? oder ist Qt4 soweit "abwärtskompatibel", dass ich das gelernte so übertragen kann? außerdem ist das für einen kleinen schüler wie mich gar nicht so wenig geld, was ich dann verschwendet hätte wenn ich das buch umsonst gekauft hätte.

mfg,
julian

Verfasst: 30. Dezember 2006 13:35
von uhu01
Hy!

Die wichtigen Dinge, wie Signal/Slots, etc. sind gleich. Du kannst ohne größere Probleme umsteigen, einige Funktionen heißen halt ein bisschen anders, bzw. sind einige Dinge dazu gekommen.

mfg
uhu01