Protokollanleitung als fertiges Paket schreiben
-
Tataaa, die grauen Zellen arbeiten wieder @ DocShoe :p
Header std::vector<unsigned char> Framesammler; unsigned int isPaketsizereached;
Main Framesammler.clear(); isPaketsizereached = 0;
std::vector<unsigned char> ReceiveBuffer( Socket->ReceiveLength(), 0 ); int recbytes = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() ); ReceiveBuffer.resize(recbytes); //Frames sammeln und anhängen bis Paket vollständig übertragen ist. Framesammler.insert(Framesammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.end()); //Hilfsvariable um Übertragungsende zu bestimmen. //Paketgröße aus dem Paketheader holen. if(Framesammler.size() >= 4) isPaketsizereached = Framesammler[4]; if(Framesammler.size() > 12 && isPaketsizereached == Framesammler.size()) { String daten = ""; for(unsigned int i = 12; i <= Framesammler.size(); i++) { daten += Framesammler[i] ; } Memo1->Lines->Add(daten) ; //Da vollständig übertragen Sammelpuffer und Paketgröße zurücksetzen für nächste Pakete Framesammler.clear(); isPaketsizereached = 0; } ReceiveBuffer.clear();
Meun DocShoe!
Mein Ziel ist nicht das abkupfern des Phytonquelltextes sondern das Wiso Weshalb Warum. Das mit dem Computerausschalten, sich mal Hinsetzen und deine Hinweiße zu befolgen hat hoffentlich anhand des hier gezeigten Ergebnisses verdeutlicht, dass es bei mir noch nicht Hoffnungslos istDer Befehl "serverinfo" sendet mehrere Pakete hintereinander und diese hängen jetzt schön aneinander im Hilfspuffer den ich dann Auslese ohne den ganzen Headerkram drin stehen zu haben.
Gestern kurz vorm einschlafen kam mir noch ein Gedanke die eigentlichen Paketdaten in 4Byte Schnipsel rauszukopieren und ein '0x' davor zu setzen um den Lösungsweg mal nach Hexadezimal zu versuchen um endlich aus dem Zahlenwirrwar Buchstaben zu erhalten. Da ich aber noch keinen genauen Anhaltspunkt habe überlege ich ob das zum Ziel führt. Was meinst du?
-
isPaketsizereached = 0;
Ist ausserdem überflüssig weil es bei entsprechender Größe eh überschrieben wird
-
Wow! Das ist ja fast gut
Ich würde die Hilfsvariable
isPaketsizereached
anders nennen, ein guter Name wäre z.B.TelegramLength
.Du hast immer noch mehrere Fehler drin:
- wenn z.B. 1.5 Telegramme in deinem Puffer stehen
darfst du nur soviele Daten entnehmen, wie das Telegramm lang ist
musst du soviele Daten aus dem Puffer entfernen, wie das Telegramm lang ist- du greifst auf den festen Index 4 des Buffers zu, da steht allerdings nur das niederwertigste Byte der Telegrammlänge drin. Richtigerweise müsstest du die Bytes der Indizes 5-7 noch berücksichtigen (und entsprechend bitshiften).
Die erste Überprüfung gegen 4 ist falsch, denn in den ersten 4 Bytes steht nur die Sequence ID und nicht die Telegrammlänge. Danach musst du gegen TelegramLength und nicht gegen 12 prüfen. Ausserdem musst du noch den Fall betrachten, dass mehrere Telegramme im Puffer stehen können.bool Done = true; do { // Annahme: kein vollständiges Telegramm im Puffer Done = true; if( FrameSammler.size() >= 4 ) { unsigned int TelegramLength = ?; if( FrameSammler.size() >= TelegramLength ) { // mach was mit´m Telegramm // entferne behandelte Daten vom Anfang des Puffers // ggf. stehen weitere Telegramme im Puffer, weiterer Durchlauf notwendig Done = false; } } } while( !Done );
Edit:
Was das die Ausgabe in´s Memo angeht: Hexadezimale Ausgabe halte ich nicht für sooo schlau, daraus erkennt man nicht viel. Klartext ist da wesentlich besser. Und wie der Zufall so will gibt´s für std::string nen schönen Konstruktor, der dir Abschnitte aus einem Vektor herausfilettiert:std::string Line( FrameSammler.begin() +x, FrameSammler.begin() +x +y ); Memo->Lines->Add( Line.c_str() );
-
Ich hab jetzt folgendes:
{ std::vector<unsigned char> ReceiveBuffer( Socket->ReceiveLength(), 0 ); int recbytes = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() ); ReceiveBuffer.resize(recbytes); //Frames sammeln und anhängen bis Paket vollständig übertragen ist. Framesammler.insert(Framesammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.end()); //Hilfsvariable um Übertragungsende zu bestimmen. //Paketgröße aus dem Paketheader holen. if(Framesammler.size() >= 4) { //Bitshift der einzelnen bytes zur Ermittlung der Paketgröße TelegramLength = Framesammler[4] >> Framesammler[5] >> Framesammler[6] >> Framesammler[7] ; } if(Framesammler.size() >= TelegramLength) { /* //Reine Telegrammlänge abarbeiten for(int x = 12; x < TelegramLength; x++) { std::string Line(Framesammler.begin() + x, Framesammler.end()); Memo1->Lines->Add(Line.c_str()); } Noch Fehlerhaft! */ bool done = false; bool deletebuffer = false; do { //Wenn im Puffer mehr als das abgearbeitete Telegram steht if(Framesammler.size() > TelegramLength) { std::vector<unsigned char> Tempbuffer; Tempbuffer.clear(); Tempbuffer.insert(Tempbuffer.end(),Framesammler.begin()+ TelegramLength,Framesammler.end()); Framesammler.clear(); Framesammler.insert(Framesammler.end(),Tempbuffer.begin(),Tempbuffer.end()); done = true; } else { deletebuffer = true; } } while(done = false); //Wenn vollständig übertragen Sammelpuffer zurücksetzen für nächste Pakete,ansonsten neu formaierten Puffer beibehalten if (deletebuffer == true) Framesammler.clear(); } ReceiveBuffer.clear(); }
//Reine Telegrammlänge abarbeiten for(int x = 12; x < TelegramLength; x++) { std::string Line(Framesammler.begin() + x, Framesammler.end()); Memo1->Lines->Add(Line.c_str()); }
Puhh, da versteh ich noch nicht so ganz wie ich an die ganzen Wörter ran komme. Wörter werden ausgegeben aber sehen noch wie folgt aus mit Leerspalten im Memo
und Sonderzeichen dazwischen:OK K 3 Server FragThe.Net is korrekte Mama - Hardcore - 1P Start! ragThe.Net is korrekte Mama - Hardcore - 1P Start! agThe.Net is korrekte Mama - Hardcore - 1P Start! gThe.Net is korrekte Mama - Hardcore - 1P Start! The.Net is korrekte Mama - Hardcore - 1P Start! he.Net is korrekte Mama - Hardcore - 1P Start! e.Net is korrekte Mama - Hardcore - 1P Start! .Net is korrekte Mama - Hardcore - 1P Start! Net is korrekte Mama - Hardcore - 1P Start! et is korrekte Mama - Hardcore - 1P Start! t is korrekte Mama - Hardcore - 1P Start! is korrekte Mama - Hardcore - 1P Start! is korrekte Mama - Hardcore - 1P Start! s korrekte Mama - Hardcore - 1P Start! korrekte Mama - Hardcore - 1P Start! korrekte Mama - Hardcore - 1P Start! orrekte Mama - Hardcore - 1P Start! rrekte Mama - Hardcore - 1P Start! rekte Mama - Hardcore - 1P Start! ekte Mama - Hardcore - 1P Start! kte Mama - Hardcore - 1P Start! te Mama - Hardcore - 1P Start! e Mama - Hardcore - 1P Start! Mama - Hardcore - 1P Start! Mama - Hardcore - 1P Start! ama - Hardcore - 1P Start! ma - Hardcore - 1P Start! a - Hardcore - 1P Start! - Hardcore - 1P Start! - Hardcore - 1P Start! Hardcore - 1P Start! Hardcore - 1P Start! ardcore - 1P Start! rdcore - 1P Start! dcore - 1P Start! core - 1P Start! ore - 1P Start! re - 1P Start! e - 1P Start! - 1P Start! - 1P Start! 1P Start! 1P Start! P Start! Start! Start! tart! art! rt! t! ! 0 32 2 ConquestSmall0 onquestSmall0 nquestSmall0 questSmall0 uestSmall0 estSmall0 stSmall0 tSmall0 Small0 mall0 all0 ll0 l0 0 MP_Subway P_Subway _Subway Subway ubway bway way ay y 0 1 2 489 89 9 489 89 9 0 true rue ue e true rue ue e false alse lse se e 26100 6100 100 00 0 20104 0104 104 04 4 EU U ams ms s DE E
Es ist mir klar das durch die for Schleife mit stetig ansteigendem X nur Salat rauskommt, aber ich möchte nur diese Funktion des std::string verstehen um es debugen zu können
-
Nach etwas Probieren bekomme ich jetzt eine halbwegs stimmige Ausgabe:
//Reine Telegrammlänge abarbeiten String temp = ""; for(int x = 16; x < TelegramLength; x++) { std::string Line(Framesammler.begin() + x , Framesammler.begin() + x + 1); temp = temp + Line.c_str(); } Memo1->Lines->Add(temp);
Die Ausgabe sieht dann wie folgt aus:
http://up.picr.de/9354907myc.jpgDie Frage ist jetzt wodurch dieser Zeichensalat zwischen den Wörtern entsteht und nicht korrekt ausgegeben wird.
Edit: Noch ein dicker Bock den ich geschossen hab:
while(done == false); //und nicht while(done = false);
Jetzt hänge ich in ner Endlosschleife fest, wenn 1,5 Frames im Buffer stehen. Daher auch der Datensalat zwischen den Wörtern
-
Die letzte überarbeitete Version für heute Nacht:
std::vector<unsigned char> ReceiveBuffer( Socket->ReceiveLength(), 0 ); int recbytes = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() ); ReceiveBuffer.resize(recbytes); //Frames sammeln und anhängen bis Paket vollständig übertragen ist. Framesammler.insert(Framesammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.end()); //Hilfsvariable um Übertragungsende zu bestimmen. //Paketgröße aus dem Paketheader holen. if(Framesammler.size() >= 4) { //Bitshift der einzelnen bytes zur Ermittlung der Paketgröße TelegramLength = Framesammler[4] >> Framesammler[5] >> Framesammler[6] >> Framesammler[7] ; } if(Framesammler.size() >= TelegramLength) { //Reine Telegrammlänge abarbeiten String temp = ""; for(unsigned int x = 16; x < TelegramLength; x++) { std::string Line(Framesammler.begin() + x , Framesammler.begin() + x + 1); temp = temp + Line.c_str(); } Memo1->Lines->Add(temp); bool done = false; do { //Wenn im Puffer mehr als das abgearbeitete Telegram steht //Wenn der Puffer das abgearbeitete Paket vollständig enthält if(Framesammler.size() >= TelegramLength) { std::vector<unsigned char> Tempbuffer; Tempbuffer.clear(); //Vollständiges und zuvor abgearbeitetes Paket im Puffer ausschneiden und folgende Daten an den Anfang stellen Tempbuffer.insert(Tempbuffer.end(),Framesammler.begin() + TelegramLength, Framesammler.end()); Framesammler.clear(); Framesammler.insert(Framesammler.end(),Tempbuffer.begin(),Tempbuffer.end()); TelegramLength = Framesammler.size(); done = true; } else { TelegramLength = Framesammler.size(); done = false; } } while(done == false); } ReceiveBuffer.clear();
Aber immernoch Headerdaten die sich im reinen Datenpuffer zwischenmogeln wenn mehrere Pakete gesendet werden. Eine Endlosschleife entsteht jetzt nicht mehr, aber die Daten werden noch genauso angezeigt wie in dem verlinkten Bild.
-
Da ist wieder jede Menge Murks dabei...
- Zeile 12-17
Du prüfst gegen Länge 4, greifst aber auf Elemente 5-8 zu. Die Bestimmung der Telegrammlänge ist zudem noch falsch. Lies dir noch ein Mal das Kapitel zum Thema bit shifts durch.- Zeile 23-30
WTF? Du baust für jedes einzelne Zeichen einen String und hängst den wieder an den Ausgabestring an. Das geht besser, weil du doch schon weißt, wie lang der String ist (steht so im Telegramm).- Zeile 43-49
Hier kommt man auch ohne temp. Puffer aus. Du sollst nur die Daten des Telegramms vom Anfang des Puffers löschen, das geht mit einemerase
Aufruf.- Zeile 52 und Zeile 58
Die korrekte Telegrammlänge ist mit Sicherheit nicht die Anzahl der verbleibenden Bytes im Empfangspuffer.also eigentlich fast alles... also nochmal von vorne. Immerhin stimmt das Empfangen und Speichern der Telegrammdaten.
- Stehen genügend Daten bereit für den Telegrammkopf (Sequence ID + Telegrammlänge. Wieviel Bytes haben 2 int32?)? Wenn nein, dann weiter bei 7)
- Telegrammlänge aus Bytes 5-8 bestimmen
- Stehen genügend Daten für das Telegramm bereit? Wenn nein, dann weiter bei 7)
- Behandle die ersten N Bytes des Puffers
- Entferne die ersten N Bytes des Puffers
- Zurück zu 1)
- Zu wenig Daten für Telegramm vorhanden
-
Meun Doc!
Soweit habe ich jetzt all deine Korrekturen umgesetzt, allerdings Blick ich durchs Bitshifting noch nicht ganz durch. Ich veranlasse einen Linksshift, aber um wieviel Bit? 1 oder alle 8 pro byte?
Zudem habe ich die Funktion noch mal grundliegend umstrukturiert, ich denke so macht es jetzt eher Sinn:
std::vector<unsigned char> ReceiveBuffer( Socket->ReceiveLength(), 0 ); int recbytes = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() ); ReceiveBuffer.resize(recbytes); //Frames sammeln und anhängen bis Paket vollständig übertragen ist. Framesammler.insert(Framesammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.end()); //Wenn der Puffer Paketdaten enthält dann prüfe und verarbeite if(Framesammler.size() > 0) { bool done = false; do { //Paketgröße aus dem Paketheader holen. //Sequence ID + Telegrammlänge. Wieviel Bytes haben 2 int32? = 8byte! if(Framesammler.size() >= 8) { //Bitshift der einzelnen bytes zur Ermittlung der Paketgröße TelegramLength = 0; TelegramLength += Framesammler[5] << 8; TelegramLength += Framesammler[6] << 8; TelegramLength += Framesammler[7] << 8; TelegramLength += Framesammler[8] << 8; // ShowMessage(TelegramLength); } else break; if(Framesammler.size() >= TelegramLength) { //Reine Telegrammlänge abarbeiten std::string Line(Framesammler.begin() + 12 , Framesammler.begin() + TelegramLength); Memo1->Lines->Add(Line.c_str()); //Vollständiges und zuvor abgearbeitetes Pakets im Puffer ausschneiden und folgende Daten an den Anfang stellen Framesammler.erase(Framesammler.begin(),Framesammler.begin() + TelegramLength); done = true; //Prüfen ob sich noch ein weiteres vollständiges Telegram im Puffer befindet //Wenn nicht, empfange weiter if (Framesammler.size() >= 8) { //Bitshift der einzelnen bytes zur Ermittlung der Paketgröße //Noch nicht angepasst, siehe oben..... TelegramLength = 0; TelegramLength = Framesammler[5] << Framesammler[6] << Framesammler[7] << Framesammler[8]; if (Framesammler.size() >= TelegramLength) continue; } else break; } else break; } while(done == false); } ReceiveBuffer.clear();
-
Zero01 schrieb:
Meun Doc!
Soweit habe ich jetzt all deine Korrekturen umgesetzt, allerdings Blick ich durchs Bitshifting noch nicht ganz durch.Nein, hast du nicht.
Zero01 schrieb:
Ich veranlasse einen Linksshift, aber um wieviel Bit? 1 oder alle 8 pro byte?
Hängt vom Byte ab. Also ganz langsam: Ein int32 besteht aus 4 Byte. Jedes dieser Bytes hat eine bestimmte Wertigkeit (zum Vergleich: Dezimalsystem. Jede Stelle besteht aus einer Ziffer, aber abhängig von der Stelle hat diese Ziffer eine andere Wertigkeit. Ein Byte ist für die Bits 0-7, eins für 8-15, noch eins für 16-23 und schließlich eins für 24-31. In deiner Protokollbeschreibung ist beschrieben, welches Byte welche Wertigkeit hat.
Zero01 schrieb:
Zudem habe ich die Funktion noch mal grundliegend umstrukturiert, ich denke so macht es jetzt eher Sinn:
Ich glaube nicht :D. Du hast viel zu viele Überprüfungen für die Telegrammgröße drin, du kommst mit nur 2 aus (Tipp: Wenn 8 oder mehr Bytes im Puffer stehen, dann stehen auch mehr als 0 Bytes drin).
Die Bestimmung der Telegrammlänge stimmt immer noch nicht, aber das weißt du ja bereits.
Bei der Softwareentwicklung macht man sich übrigens vorher Gedanken zum Algorithmus und setzt diesen dann in Code um. Man probiert nicht solange, bis es irgendwann zufällig funktioniert. Du machst letzteres...Langsam gehe ich auf dem Zahnfleisch... vielleicht erbarmt sich ja jemand anderes, das hier zu lösen, ich kann langsam nicht mehr
-
DocShoe schrieb:
Langsam gehe ich auf dem Zahnfleisch... vielleicht erbarmt sich ja jemand anderes, das hier zu lösen, ich kann langsam nicht mehr
Oh nicht wegen mir. Entschuldige bitte
Ich weiß das ich einiges noch nicht ganz durchblicke und evtl. auch dafür zu doof bin momentan strukturiert vor zu gehen. Ich versuchs trotzdem zu lösen.
Ich danke dir tausendfach für deine Hilfe
-
int32 size;
Hat im empfangenen Paket 4 byte Felder zu je 8 Bit. Das erste Byte ist das
niederwertigste, das vierte das höchstwertigste. Man könnte doch angefangen vom niederwertigsten Byte mit bitweise AND bis zum höchstwertigen Verknüpfen um die Ganzzahl int32 zu erhalten. Ist das so Richtig?
-
*Röchel* Na... gut... bevor ich wahnsinnig werde:
#include <string> #include <vector> #include <iostream> #include <iterator> struct Packet { unsigned int Sequence; std::vector<std::string> Words; Packet() : Sequence( 0 ) { } }; void handle_packet( const Packet& Packet ) { std::cout << "Packet Sequence : " << std::hex << "0x" << Packet.Sequence << "\n"; std::copy( Packet.Words.begin(), Packet.Words.end(), std::ostream_iterator<std::string>( std::cout, "\n" ) ); } void handle_packets( std::vector<char>& Buffer ) { // Telegrammlänge steht in Bytes 5-8, daher müssen mindestens // 8 Byte im Puffer stehen while( Buffer.size() >= 8 ) { // Telegrammlänge bestimmen. unsigned int TelegramLength = Buffer[4] | Buffer[5] << 8 | Buffer[6] << 16 | Buffer[7] << 24; // stehen genügend Daten im Puffer für das komplette Telegramm? Wenn nein, dann abbrechen if( Buffer.size() < TelegramLength ) return; Packet Packet; // Sequence steht in den ersten 4 Byte des Telegramms Packet.Sequence = Buffer[0] | Buffer[1] << 8 | Buffer[2] << 16 | Buffer[3] << 24; // Anzahl der Wörter steht in Bytes 9-12 unsigned int WordCount = Buffer[8] | Buffer[9] << 8 | Buffer[10] << 16 | Buffer[11] << 24; // Zeiger auf Länge des 1. Wortes setzen char* WordPtr = &Buffer[12]; // Wörter isolieren for( unsigned int i = 0; i < WordCount; ++i ) { // Wortlänge steht in den ersten 4 Bytes unsigned int WordLength = WordPtr[0] | WordPtr[1] << 8 | WordPtr[2] << 16 | WordPtr[3] << 24; // Inhalt des Strings in Paket einfügen. Inhalt des Strings steht ab Byte 4 // abschließendes Nullbyte ausnutzen, um aus char* einen std::string zu erzeugen Packet.Words.push_back( WordPtr +4 ); // Wort überspringen (tatsächliche Wortlänge + 4 Byte für Präfix + 1 Byte abschließende 0) WordPtr += 4 + WordLength +1; } // Telegrammdaten aus Puffer entfernen Buffer.erase( Buffer.begin(), Buffer.begin() + TelegramLength ); // Packet behandeln handle_packet( Packet ); } } void receive_packets( std::vector<char>& Buffer ) { std::vector<char> ReceiveBuffer( Socket->ReceiveLength(), 0 ); if( !ReceiveBuffer.empty() ) { int Received = Socket->Receive( &ReceiveBuffer[0], ReceiveBuffer.size() ); if( Received > 0 ) { TelegramBuffer.insert( Buffer.end(), ReceiveBuffer.begin(), ReceiveBuffer.begin() + Received ); handle_packets( Buffer ); } } } int main() { std::vector<char> TelegramBuffer; receive_packets( TelegramBuffer ); handle_packets( TelegramBuffer ); }
Live and learn, young Padawan.
Edit:
Ohne Netz und doppelten Boden. Bei kaputten Telegrammen kann dir das um die Ohren fliegen, weil keine Plausibilitätsprüfung für Zeiger gemacht wird.
-
Wow, das muss ich erstmal sacken lassen... Ich schreibe erst weiter wenn ich verstanden habe wo meine Fehler waren. Danke Doc
-
Mit dem linksshift war ich ja schonmal nicht ganz so falsch. Auf der rechten Seite des shifts steht die Anzahl N der Bits um die verschoben werden soll...auch noch nachvollziehbar. Ich verstehe das Bitweise OR in seiner Funktion hier einfach nicht
-
Zero01 schrieb:
Ich verstehe das Bitweise OR in seiner Funktion hier einfach nicht
Ach, komm´ schon, das ist trivial. Nimm dir´n Blatt Papier und ´nen Stift und mach´ das Ganze ein Mal von Hand. Hier die Wahrheitstabelle für OR, falls das das Problem sein sollte.
| 0 | 1 | ---+---+---+ 0 | 0 | 1 | ---+---+---+ 1 | 1 | 1 | ---+---+---+
-
Danke Doc
hab ein nettes Tutorial zum Thema Bitverschiebung gefunden und weiß jetzt, bezogen auf deine Tips, wie es verwendet wird. Ist im nachhinein auch ne klare Sache wenn ein Wert über mehrere Byte zusammenhängen geschrieben oder gelesen wird. Ich danke dir von ganzem Herzen für deine beispiellose Hilfe. Das Know How durch diesen Thread hat mich ein gutes Stück weiter gebracht
-
Hey Doc!
ich bin auf ein Problem gestossen. Wenn
die SequenceID 0x00000001 ist dann baue
ich mir doch in den stringstream ungewollt einen wertlosen stringterminator ein (0x00)
-
In meinem Code taucht nirgendwo ein
stringstream
auf, also musst du was dazugebastelt haben.
-
Sorry
ich meinte den ostringstream
-
Werd´ bitte mal etwas genauer, ich habe keine Ahnung, wo dein Problem liegt.