[gelöst] Welche der Varianten zum Senden von Daten über TCPS

Alles rund um die Programmierung mit Qt
Antworten
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

[gelöst] Welche der Varianten zum Senden von Daten über TCPS

Beitrag von Rumbert »

Hallo miteinander,

nach meinem Post: "Zuviel Daten für QTcpSocket?" bin ich nun total verwirrt und wollte einmal grundsätzlich Nachfragen, was nun richtig ist, um Daten über einen TCPSocket zu schicken. Mit Hilfe des Forums, des Internets und Literatur bin ich auf zahlreiche Lösungsansätze gestoßen, von denen ich nun nicht weiß, welche überhaupt nicht gehen können und welche wo ihre Vor- und Nachteile haben. Hier nun meine fünf Varianten zum übertragen der Bildgröße und des QImages.

Code: Alles auswählen


// ###  1  ###
void VideoServer::slotSendMessage(const QImage& image)
{
	QByteArray baImage;
	QBuffer buffer(&baImage);
	buffer.open(QIODevice::WriteOnly);
	image.save(&buffer, "JPG"); 
	
		QDataStream directOut(connectedSockets[1]);
		// Übertragen der Bildgröße
		directOut << (quint16)baImage.size();
    // übertragen des Bildes
		connectedSockets[1]->write(baImage);
}


// ###  2  ###
void VideoServer::slotSendMessage(const QImage& image)
{
	QByteArray baImage;
	QBuffer buffer(&baImage);
	buffer.open(QIODevice::WriteOnly);
	image.save(&buffer, "JPG"); 
		
		QDataStream directOut(connectedSockets[1]);
		// Übertragen der Bildgröße
		directOut << (quint16)baImage.size();
    // übertragen des Bildes
    directOut << baImage;	
}


// ###  3  ###
void VideoServer::slotSendMessage(const QImage& image)
{
	QByteArray baImage;
	QByteArray block;
	QBuffer buffer(&baImage);
	buffer.open(QIODevice::WriteOnly);
	image.save(&buffer, "JPG"); 
		
		QDataStream directOut(connectedSockets[1]);
		// Übertragen der Bildgröße
		directOut << (quint16)baImage.size();
		// übertragen des Bildes
		QDataStream out(&block, QIODevice::WriteOnly);
		out << baImage; 	
}


// ###  4  ###
void VideoServer::slotSendMessage(const QImage& image)
{
   QByteArray baImage;
   QByteArray block;
   QBuffer buffer(&baImage);
   buffer.open(QIODevice::WriteOnly);
   image.save(&buffer, "JPG");

      QDataStream out(&block, QIODevice::WriteOnly);
      // Übertragen der Bildgröße
      out << (quint16)baImage.size();
      // übertragen des Bildes
      out << baImage;
      connectedSockets[1]->write(block);
} 


// ###  5  ###
void VideoServer::slotSendMessage(const QImage& image)
{
  QByteArray baImage;
  QByteArray block;
  QBuffer buffer(&baImage);
  buffer.open(QIODevice::WriteOnly);
  image.save(&buffer, "JPG");
     
      QDataStream directOut(connectedSockets[1]);
      // Übertragen der Bildgröße
      directOut << (quint16)baImage.size();
       // übertragen des Bildes
      QDataStream out(&block, QIODevice::WriteOnly);
      out << baImage;
      connectedSockets[1]->write(block);
}
Über Erklärungen, Kommentare und Hinweise zu den Codebeispielen wäre ich sehr Dankbar!
Alternativ Beispiele sind auch sehr Willkommen :-)

Grüße Rumbert
Zuletzt geändert von Rumbert am 16. Juni 2009 17:38, insgesamt 1-mal geändert.
Mani99
Beiträge: 244
Registriert: 15. April 2009 10:46
Wohnort: München

Beitrag von Mani99 »

Also ich würde sage, version 1 macht nichts anderes als nur die größe des bildes zu versenden, und version 3 bis 5 werden warscheinlich auch nichts brauchbares machen, also bleibt nur noch version 2 über!

Code: Alles auswählen

void VideoServer::slotSendMessage(const QImage& image)
{
   QByteArray baImage;
   QBuffer buffer(&baImage);
   buffer.open(QIODevice::WriteOnly);
   image.save(&buffer, "JPG");
      
      QDataStream directOut(connectedSockets[1]);
      // Übertragen der Bildgröße
      directOut << (quint16)0;
    // übertragen des Bildes
    directOut << baImage; 
    directOut<<((quint16)baImage.size-sizeof(quint16));
}
Wäre ein guter anfang!
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

Hallo Mani99,

warum sollte in Beispiel 1 nur die Größe übertragen werden?
Der QTcpSocket ist ja letzlich von QIODevice abgeleitet und dieser bietet die Methode write. Dazu sagt die Hilfe:

qint64 QIODevice::write ( const QByteArray & byteArray )
This is an overloaded member function, provided for convenience.
Writes the content of byteArray to the device. Returns the number of bytes that were actually written, or -1 if an error occurred.

Und der Debugger sagt für:

Code: Alles auswählen

		directOut << (quint16)baImage.size();
		qDebug() << (quint16)baImage.size();
		qint64 amountBytes = connectedSockets[i]->write(baImage);
dass die amountBytes mit der image Größe übereinstimmt.

Worin liegt denn prinzipiell der Unterschied zwischen dem Verschicken der Daten über einen "QDataStream" oder mittels "socket->write(...)"?

Grüße Rumbert
Mani99
Beiträge: 244
Registriert: 15. April 2009 10:46
Wohnort: München

Beitrag von Mani99 »

Also so der pro bin ich auch nicht, ich weiß nur was bei mir funktioniert.

Code: Alles auswählen

// ###  1  ###
void VideoServer::slotSendMessage(const QImage& image)
{
   QByteArray baImage;
   QBuffer buffer(&baImage);
   buffer.open(QIODevice::WriteOnly);
   image.save(&buffer, "JPG");
   
      QDataStream directOut(connectedSockets[1]);
      // Übertragen der Bildgröße
      directOut << (quint16)baImage.size();
    // übertragen des Bildes
      connectedSockets[1]->write(baImage);
} 
Hier drückst du das bild in ein bytearray rein, danach erstellst du einen QDataStream vom socket und übergibst dem datastream die größe des bildes und danach schickst du das das bytearray des bildes ohne den QDataStream über den socket irgendwohin.

Bei mir funktioniert das senden von datan so:

Code: Alles auswählen

//QTcpServer *server;
QTcpSocket *sock = server->nextPendingConnection();

QByteArray baImage;
QBuffer buffer(&baImage);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG");


QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out<<(quint16)0;
out<<baImage;
out<<((quint16)block.size()-sizeof(quint16));

sock->write(block);
Sehr vereinfacht ausgedrückt funktioniert das senden von daten bei mir so!
Nailgun
Beiträge: 22
Registriert: 3. März 2009 11:59

Beitrag von Nailgun »

@Mani: Kann es sein, dass du beim Schreiben der größe des Packets vergessen hast wieder vor das eigenliche Packet zu springen(qdatastream.device()->seek(0))?

Aber sonst mach ich es auch so wie Mani. Zum überlegen wär noch ob du die Bilder in kleinen Packeten verschickst, dass sie nicht immer komplett im Speicher liegen müssen.

mfg Chris
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

Was ich nun noch nicht so verstehe ist, wozu ich das Bild erst in ein QDataStream packen muss.
Denn:

Code: Alles auswählen

QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly); 
out<<baImage;
[...]
sock->write(block); 

//versus

 QByteArray baImage;
[...]
sock->write(baImage); 
in beiden Fällen schicke ich mittels write ein QByteArray. Steht nicht in beiden QByteArrays "block" und "baImage" exakt das selbe, sofern ich in Fall 1 nichts weiteres in den Stream packe (soll heißen kein weiteres out<<... ) ?

Grüße Rumbert

p.s. und vielen Dankl für Eure Hilfe!
Nailgun
Beiträge: 22
Registriert: 3. März 2009 11:59

Beitrag von Nailgun »

In deinem baImage stehen die Bytes des Bildes drin. Und wenn du nur das in den Stream schreibst dann steht im block auch nichts anderes drin. Aber du willst doch sicher der Gegenstelle vorher mitteilen wie groß das ankommende Packet sein wird. Und genau diese Größe schreibts du in block vor den eigentlichen Bildbytes.
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

Also verwende ich den QDataStream nur um quasi komfortabel ein QByteArry füllen zu können? Also könnte ich genauso gut die Bildgröße in ein eigenes QbyteArray Speichern und dann mittels
QByteArray & QByteArray::append ( const QByteArray & ba )
das QByteArray des Image konkatenieren und als Block verschicken?

Wenn ich das nun richtig sehe muss die Packetgröße immer in dem selben Block stehen der auch das Bild enthält? Kann ich nicht erst einen Block schicken der sagt, der Nächste Block hat die Größe X? Und danach das entsprechende Bild als zweiten Block?

Grüße Rumbert
Mani99
Beiträge: 244
Registriert: 15. April 2009 10:46
Wohnort: München

Beitrag von Mani99 »

@Nailgun:

Jo, hab das seek(0) vergessen, danke! :D

@Rumbert:

In einen datastream kannst du mehrere infos reinschreiben.

Code: Alles auswählen

QString testStr("Das ist ein Test");
QString testStr2("Noch ein Test");
QByteArray block;

QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_5);
out<<(quint16)0;
out<<baImage;
out<<testStr.toUtf8();
out<<testStr2.toUtf8();
out.device()->seek(0);
out<<(quint16)(block.size() - sizeof(quint16));
[...]
sock->write(block); 
und auf der anderen seite:

Code: Alles auswählen

QByteArray img;
QByteArray str1;
QByteArray str2;
quint16 mn;
quint16 size;

QDataStream in(-device_von_dem_gelesen_wird-);
in.setVersion(QDataStream::Qt_4_5);
in>>mn>>img>>str1>>str2>>size;
[...]
Alles sehr vereinfacht ausgedrückt.
Nailgun
Beiträge: 22
Registriert: 3. März 2009 11:59

Beitrag von Nailgun »

Das mit Append sollte auch gehen, da ja im Endeffekt wieder ein ByteArray rauskommt.

Du darfst hier die Größe nicht mit der Größe des Bildes verwechseln. Ich mein damit die Größe des zu empfangenden Packets. Als Beispiel:
Du hast ein Bild das 1024kb groß ist. Weil mir das zu groß ist um es aufeinmal zu versenden, zerlege ich das Bild in 4 Teile a 256kb

Jetze schicke ich 4 Packete (ByteArray) raus, wobei jedes gleich aufgebaut ist. [(größe des Packets, also hier 256)(256bytes des Bildes)]
die Gegenstelle weis jetzt, dass sie solange warten muss bis die Größe eines quint16 zu lesen ist. Ist diese verfügbar, les ich das aus dem Stream und speichere mir es in ne Variable. Jetzt warte ich solange bis ich soviel Bytes lesen kann wie in der Variable steht. Damit hab ich das ganze packet empfangen. dann kommt das zweite usw.

Im Großen und ganzen sieht das dann so aus:
(Länge der Nutzdaten)(Nutzdaten)(Länge der Nutzdaten)(Nutzdaten)...
was jetzt in den Nutzdaten steht ist dir überlassen.

Hm ich hoff das war verständlich :-)
Antworten