ByteArry als Container per tcp

Alles rund um die Programmierung mit Qt
Antworten
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

ByteArry als Container per tcp

Beitrag von dazedly »

Ich habe ein Problem mit dem QByteArray, wenn ich es über tcp schicke.
Ich kann es auf der Anderen Seite nicht wirklich annehmen, bzw ist es irgendwie leer.

Code: Alles auswählen

QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_7);

int id = 1;

out << id;

QByteArray byebye;
QDataStream bin(&byebye, QIODevice::ReadWrite);
bin.setVersion(QDataStream::Qt_4_7);
bin << QString("twts");
bin << QStrint("sadads");

out << byebye;

out<< QString("Ende");

this->clientConnection->write(out);
	
this->clientConnection->flush();
Das zweite ByteArray ist wichtig, da ich einen eigenen Container für den Inhalt brauche. Die Funktion die damit umgeht brauch nicht zu wissen, was da drin ist, nur was danach kommt. Ich hab verschiedene Arten von Paketen und zwischen denen muss ich unterscheiden. Eins davon muss wie gesagt ein ByteArray enthalten (oder ähnliches), welches ich einfach weiterleiten kann.

Code: Alles auswählen

Client:
..........
QByteArray byte;
in >> byte;
......
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Das senden sieht prinzipiell ok aus, also heisst es muesste funktionieren ... wenn die verbindung korrekt steht.

Das empfangen sieht eher mysterious aus !

was ist "in" ? Ein IODevice ? (QSocket z.b.);

prinzipiell muesstest du dein "Protokoll aufbohren"

wann beendet sich die connection ?
schickst du mehr als 1 QByteArray ?

prinzipiell verschickst du bei TCP byteweisse daten. TCP garantiert Dir nur, das die daten in folge und das alle ankommen, nicht in welchen blockgroessen die uebermittlung geschieht. also auf der Empfangsseite musst du wissen, wenn dein QByteArray zu ende ist ... und solange musst du alle daten in Deinem ByteArray sammeln ...
Also ggf. eine endekennung schicken.

wenn "in" ein IODvice ist wuerde das so ca. aussehen:

Code: Alles auswählen

QByteArray byte;
bool bEndDetected = false;
while(!bEndDetected) 
{
     QByteArray bufferIn = in.readAll();
     /// hier checken ob endekennung mit bei war ? 
    if(endDectect(bufferIn)) bEndDetected = false;
    // die gelesenen Daten trotzdem an das byteArray dranhaengen ... 
    byte += bufferIn;
}
/// hier hasst dein empfangenes Array eigentlich zusammengebeut 
/// also kannst hier das auslesen beginnen 
QDataStream bin(&byte, QIODevice::Read); 
QString strBuffer;
bin >> strBuffer; // 1 String .... 

.... 
bis zum letzten string halt 
Wenn Deine enpfangsfunktion nicht weiss, was sie bekommt, so muss sie aber wissen was zu einem block gehoert und was nicht ....

Aber eigentlich nimmt dir QDataStream auch das ab ...

versende mal so:

QDataStream out(this->clientConnection, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_7);
Dann kannst dir das schreiben auf den socket direkt sparen ...

und dein einlesen ins bytearray ueber den datenstrom wuerde auch funktionieren ...

Ciao ...






Ciao ...
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Beitrag von dazedly »

Ich Schicke das Endre Schon mit und kann es ohne Probleme erkennen.

Code: Alles auswählen

Verbunden 
read 
Type  "Response" 
ID  1223 
Code  0 
ResponseSize  1008 
"" 
"ResponseEnd"
Das leere "" ist ein missglückter Versuch mein ByteArray zu lesen.

Auf dem Server baue ich es so zusammen:

Code: Alles auswählen

 	QByteArray byebye;
	QDataStream bin(&byebye, QIODevice::ReadWrite);
	bin.setVersion(QDataStream::Qt_4_7);
	bin << QString("twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs twtsadfasdfsdfdsfs ");
	bin << QString("twtsadfasdfsdfdsfs");
	bin << QString("twtsadfasdfsdfdsfs");
	bin << QString("twtsadfasdfsdfdsfs");
Auf dem Client bekomme ich mit "barray.count("t");" 26 raus. Was den 26 "t" aus meinem ByteArray übereinstimmt.

Nur funktioniert folgendes nicht:

Code: Alles auswählen


QDataStream ins(bytes);
ins.setVersion(QDataStream::Qt_4_7);
QString str;
ins >> str;
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

DU kommst irgendwie mit Deiner Hirarchie von QString in QByteArray durcheinander !

wenn du einen QByteArray in einen Strom schickst, kannst du kein QString auslesen wollen.

Die frage ist nur, was genau schickst du rein ?
this->clientConnection->write(out);
das genau schickt eben nicht das ByteArray inklusive kennungen, sondern nur den Inhalt als ByteStrom.

wenn du mit write (writeout etc) schreibst, solltest du entsprechend auch mit read (readAll etc ) lesen ... und Dir der Konsequenzen bewusst sein.

wie liesst Du das auessere Array ? bzw wo ist dein read ?

WIe gesagt mein Vorschlag waer, nicht mit read zu arbeiten sondern den ausseren Datenstrom direkt auf den "Socket" arbeiten lassen ...

Ciao ...
dazedly
Beiträge: 197
Registriert: 3. Oktober 2010 15:38
Kontaktdaten:

Beitrag von dazedly »

Ich glaube ich war nicht genau genug.

Code: Alles auswählen

qDebug()<<"read";
	QDataStream in(this->tcpSocket.readAll());
	in.setVersion(QDataStream::Qt_4_7);
	
	QString type;
	
	quint64 code;
	QString end;
	
	in >> type;
Das ist ein Ausschnitt vom client. Das ByteArray, von dem ich spreche, kommt nach der innerhalb des Streams und beinhaltet in diesem fall verschiedene Strings. Es ist aber egal, was da rein soll, da ich die daten hier nur an eine Klasse übergebe.
trendyAndy
Beiträge: 54
Registriert: 27. März 2009 15:01

Beitrag von trendyAndy »

Hallo,

also das was RHBaum da geschrieben hat, hat mir eben unglaublich weiter geholfen.

Ich habe zuerst auch nicht direkt auf den socket geschrieben, sondern den Umweg über ein Byte Array gemacht:

Code: Alles auswählen

QByteArray block
QDataStream out(&block, QIODevice::WriteOnly);
...
out << UintData; // Ein QVector<quint32> mit 100Werten
out << IntData2; // Ein QVector<qint32> mit 100Werten
...
socket->write(block);
...
Quint32 sind ja 4 Byte. Jetzt würde ja jeder erwarten, dass bei

Code: Alles auswählen

qDebug() << block->size();
als Ergebnis 800 ausgegeben wird. Dem ist aber nicht so. es sind 808.
Das konnte ich mir nur so erklären, das eine Information eingefügt wird. Anfangkennung, Variablentyp oder was weiß ich. Tests gemacht und so wars dann auch. Deshalb kann man dann wohl beim einlesen dann so vor gehen wie es in allen Beispielen in der Hilfe drin ist:


Code: Alles auswählen

...
QDataStream in(ClientConnection)
...
//Warten bis alle Bytes da sind usw.
ClientConnection->waitForReadyRead(500);
...
QVector<quint32> V1; //Mit Vorzeichen
QVector<qint32> V2; //Ohne Vorzeichen
in >> V1;
in >> V2;
...
Und es wird alles automatisch verwurstet das die Uint´s in V1 rein kommen und die Int´s in V2.
Oder liege ich da falsch :?:

Na jedenfalls konnt ich das gar nicht brauchen weil ich mit nem Mirkocontroller über TCP/IP kommuniziere. Jetzt wo ich es direkt auf den Socket schreibe passt es und es kommen auch wirklich 800 Bytes an die ich dann selber verarbeiten bzw. trennen muß.

Danke an RHBaum :lol:

Gruß
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Und es wird alles automatisch verwurstet das die Uint´s in V1 rein kommen und die Int´s in V2.
Nen "Datenstrom" stellt die Integritaet an seinen Kommunikationspunkten sicher, garantiert aber nix was den Inhalt der Daten angeht, die uebertragen werden.

Bei vectoren kannst dir 100% sicher sein, dass er marken uebertraegt wo er dann weiss wann der vector zuende ist und wann nich ...

weiterhin übertraegt QDataStream die daten Plattformunabhaengig.
Das heisst nen int den auf ner Intel plattform reinschickst und den Wert 64 hat, wird auf ner Motorola plattform so als int rauskommen, dass er da auch den Wert 64 hat. Obwohl die bitfolgen eigentlich anders aussehen muessten :-)

Also QDatenstrom nuetzt dir nur etwas, wenn auf eingangs und ausgangsseite eine zueinander kompatible version des QDatenstrom verwendest. Kannst das nicht, dann musst soweiso raw auf den socket schreiben ...

Ciao ...
trendyAndy
Beiträge: 54
Registriert: 27. März 2009 15:01

Beitrag von trendyAndy »

weiterhin übertraegt QDataStream die daten Plattformunabhaengig.
OK, soweit wußte ich das auch.
Obwohl die bitfolgen eigentlich anders aussehen muessten
Du meinst dass ich die auf Little Endian umstellen mußte? Denn das hatte ich beim testen bemerkt.

So weit so gut, oder so schlecht, denn das mit dem raw schreiben blicke ich leider noch nicht. Kannst da mal kurz nen Codeschnipsel als Denkanstoß posten?

Also habe ich dich richtig verstanden. Verbindung von PC über TCP/IP zu nem controller kannste QDataStream vergessen?

gruß
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Also habe ich dich richtig verstanden. Verbindung von PC über TCP/IP zu nem controller kannste QDataStream vergessen?
Jein ...

Aber ich denke auf der Mikrokontroller-Seite hasst kein Qt, oder ? wenn nein, dann vergiss QDataStream.

Zur bytefolge:
wenn du ne andere Zielplattform hasst, also INTEL auf Motorola, oder generell Big Endian zu Little Endian kommen die werte alle Variablen, die du direkt in den socket schreibst, auf der anderen seite verkehrt rum raus.

wenn du alles nur 1 Byte weisse verschickst, dann passiert nix :-)

Also wenn du nen int in nen Socket schreibst ala
QAbstractSocket::write(&MyInt,sizeof(int));
und auf der gegenseite wieder ausliest QAbstractSocket::read(&MyInt,sizeof(int));
sind die DInger verdreht ....

Wenn du mit QByteArray als zwischenpuffer arbeitest, verschiebt sich das problem natuerlich ins befuellen des Buffers ....

Um daten plattformunabhaengig zu uebertragen, ist fuer Netzwerkverbindungen eine generelle ByteOrder festgelegt.
Um Daten dahingehend zu convertieren stellt jede API funktionalitaet zur verfügung.
Posix und Winapi: htonl -> Host to Network Order für long
für andere Integer Typen usw gibts auch was ....
ASCII string sind eher unkritisch, da 1 byte ausrichtung.
Unicode, besonders mit wechselnder zeichenbreite -> horror, fuer netzwerk eigentlich ungeeignet.
Flieskomma zahlen, auch ungeeignet, weil es unterschiedliche formate gibt /geben kann.
Normal uebertraegt man fliesskomma zahlen dann ueber mathematische methoden wo sie auf ints + berechnungsvorschrift aufgeloest werden.

Ciao ...
Antworten