Protokollanleitung als fertiges Paket schreiben
-
Hallo Leute!
ich bin schon seit Jahren aus der Praxis draussen und möchte mich mal wieder an ein Projekt ranwagen. Ich habe eine Dokumentation wie ein Paket aufgebaut sein muss, aber leider noch keine Idee wie man anhand dieser Anleitung das Paket in Quelltext fasst. Ich hoffe, das ihr mir weiterhelfen könnt. Die Anleitung sieht wie folgt aus:Packet format:
int32 32-bit unsigned integer 1 byte bits 7..0 of value 1 byte bits 15..8 of value 1 byte bits 23..16 of value 1 byte bits 31..24 of value Word int32 Size Number of bytes in word, excluding trailing null byte. char[] Content Word contents -- must not contain any null bytes. char Terminator Trailing null byte. Packet int32 Sequence Bit 31: 0 = The command in this command/response pair originated on the server 1 = The command in this command/response pair originated on the client. Bit 30: 0 = Request, 1 = Response Bits 29..0: Sequence number (this is used to match requests/responses in a full duplex transmission). int32 Size Total size of packet, in bytes. int32 NumWords Number of words following the packet header. Word[N] Words N words A packet cannot be more than 16384 bytes in size.
Kann mir bitte jemand helfen das ganze in Quelltext zu fassen damit ich mal den Buzug zueinander verstehe. Ich weiß momentan gar nicht wie ich anfangen soll
-
Sooo, ich habe nun endlich ne Idee gehabt und habe angefangen:
struct Word { unsigned int Size; char Content[128]; char Terminator; }; struct Paket { unsigned int Sequence; unsigned int Size; unsigned int NumWords; Word words[]; };
Und nun die Anwendung dessen:
Word Inhalt; Paket Datenpaket; strcpy(Inhalt.Content,"login.plainText Passwort"); Inhalt.Terminator = 0; Inhalt.Size = 128; Datenpaket.Sequence = 22222222222222222222222222222201; Datenpaket.Size = sizeof(Datenpaket); Datenpaket.NumWords = 2; ClientSocket1->Socket->SendBuf((char*)&Datenpaket,sizeof(Datenpaket));
Aber leider funktioniert es nicht und ich weiß momentan nicht woran es liegt.
Hier ist die originale PDF Datei der Protokollbeschreibung:
http://hotfile.com/dl/142949213/b431df4/BF3_PC_Server_Remote_Administration_Protocol.pdf.html
-
Ich hab mir jetzt das PDF _nicht_ angeschaut, jedoch vermute ich, daß die Daten per Ethernet verschickt werden sollen.
Hierbei ist darauf zu achten, daß die Struktur gepackt wird.
D.h. das die Daten alle hintereinander im Speicher liegen und dann auch so verschickt werden.
Deine struct Word wird vermutlich als 3x32 Bit Wert im Speicher abgelegt sein, was durch das Packen verhindert wird.Im Builder geht das Packen so:
#pragma pack(push,1) //packen beginnen struct Word { unsigned int Size; char Content[128]; char Terminator; }; struct Paket { unsigned int Sequence; unsigned int Size; unsigned int NumWords; Word words[]; }; #pragma pack(pop) //packen beenden
Ein weiterer Tipp, was bezüglich Ethernet, meiner Meinung nach, sehr wichtig ist, schau dir das Programm Wireshark an. Dies ist ein Ethernet Sniffer, womit Du sehen kannst, was deine Anwendung wirklich verschickt.
Viel Erfolg.
MfG Stephan
-
Das kann so auch nicht funktionieren, weil deine char Arrays immer eine fixe Länge von 128 haben. Im Protokoll ist definiert, dass jedes Word ein Attribut
Content
hat, das von genau einem abschließenden Nullbyte terminiert wird. Eigentlich brauchst du keine eigene Datenstrukturen für dein Paket, denn im Grunde sind die Daten nur Zeichenketten, die in einem bestimmten Format abgesendet werden. Um ein Paket zusammenzubauen kannst du Klassen der STL benutzen:#include <string> #include <iostream> #include <sstream> #include <iterator> #include <vector> std::string make_packet( unsigned int Sequence, const std::vector<std::string>& words ) { // 1. Schritt: Paketlänge bestimmen unsigned int TotalSize = 4; // 4 Byte für Paketheader for( std::vector<std::string>::const_iterator it = words.begin(); it != words.end(); ++it ) { TotalSize += 4; // 4 Byte für Länge des Wortes TotalSize += it->size(); // Anzahl der Zeichen des Wortes TotalSize += 1; // 1 Byte für abschließende 0 } TotalSize += 4; // 4 Byte für Anzahl der Wörter TotalSize += 4; // 4 Byte für Gesamtgröße des Pakets std::ostringstream oss; // Sequence ID (oder was auch immer) schreiben oss << static_cast<char>( Sequence & 0xff ) << static_cast<char>( (Sequence >> 8) & 0xff ) << static_cast<char>( (Sequence >> 16) & 0xff ) << static_cast<char>( (Sequence >> 24) & 0xff ); // Gesamtgröße schreiben oss << static_cast<char>( TotalSize & 0xff ) << static_cast<char>( (TotalSize >> 8) & 0xff ) << static_cast<char>( (TotalSize >> 16) & 0xff ) << static_cast<char>( (TotalSize >> 24) & 0xff ); // Anzahl der Wörter schreiben oss << static_cast<char>( words.size() & 0xff ) << static_cast<char>( (words.size() >> 8) & 0xff ) << static_cast<char>( (words.size() >> 16) & 0xff ) << static_cast<char>( (words.size() >> 24) & 0xff ); // Wörter selbst schreiben for( std::vector<std::string>::const_iterator it = words.begin(); it != words.end(); ++it ) { // Anzahl der Zeichen im Wort schreiben oss << static_cast<char>( it->size() & 0xff ) << static_cast<char>( (it->size() >> 8) & 0xff ) << static_cast<char>( (it->size() >> 16) & 0xff ) << static_cast<char>( (it->size() >> 24) & 0xff ); // Wort schreiben oss << *it; // abschließendes 0-Byte schreiben oss << static_cast<char>( 0 ); } return oss.str(); } int main() { std::vector<std::string> Words; Words.push_back( "Hello" ); Words.push_back( "World" ); std::string Packet = make_packet( 1, Words ); }
Du kannst dein Packet natürlich auch als Klasse modellieren und den Stream operator überladen:
struct Packet { unsigned int Sequence; std::vector<std::string> Words; Packet() : Sequence( 0 ) { } Packet( unsigned int Sequence ) : Sequence( Sequence ) { } }; ostream& operator<<( ostream& os, const Packet& op ) { // Code siehe make_packet }
}
-
Vielen Dank euch beiden!
@DocShoe:
Hast du schonmal mit dem Rcon Protokoll gearbeitet?Der Server gibt immer noch keine Antwort aus, aber er kickt mich wenn ich mehrere Packete hintereinander sende:
unsigned char *buff; std::vector<std::string> Words; Words.push_back( "login.plainText password"); std::string Packet = make_packet( 3, Words ); strcpy(buff ,Packet.c_str()); ClientSocket1->Socket->SendBuf(buff, sizeof buff);
Kann es sein das die Standard TCP Client Komponente von der BCB
Auswahl nicht mit gängigen Standards zurecht kommt und nur der BCB TCP Client mit dem BCB TCP Server kommunizieren kann?
-
std::vector<std::string> Words; Words.push_back( "login.plainText password"); std::string Packet = make_packet( 0, Words ); ClientSocket1 -> Host= "210.198.162.241"; ClientSocket1 -> Port= 27505; ClientSocket1 -> Open(); ClientSocket1->Socket->SendBuf((char*)&Packet,sizeof(Packet) );
Die Logindaten entsprechen nicht der Realität in diesem Beispiel. So wie es aussieht kommt das Paket richtig beim Server an, da ich nun direkt ein disconnect bekomme wenn ich dieses erneut sende. Aber wie bewege ich das ClientSocket dazu Daten entgegenzunehmen?
-
Zero01 schrieb:
Vielen Dank euch beiden!
@DocShoe:
Hast du schonmal mit dem Rcon Protokoll gearbeitet?std::string Packet = make_packet( 3, Words ); strcpy(buff ,Packet.c_str()); ClientSocket1->Socket->SendBuf(buff, sizeof buff);
Nein, habe ich nicht.
Du kannst strcpy hier nicht verwenden, da es sich bei dem Puffer nicht um Klartext sondern um Binärdaten handelt. Dabei ist es sehr wahrscheinlich, dass der Puffer mehrere Nullbytes enthält undstrcpy
ab dem ersten nicht mehr weiterkopiert. Ersetz´ den zitierten Code mal durchstd::string Packet = make_packet( 3, Words ); if( !Packet.empty() ) { ClientSocket1->Socket->SendBuf( &Packet[0], Packet.size() ); }
-
Super!!! ich weiß gar nicht wie ich dir danken soll. Der Server kommuniziert nun endlich mit meinem Client. Jetzt muss ich nur noch deine Funktion wie das Paket formatiert wird richtig verstehen um das Paket vom Server wiederum zu entschlüsseln
-
Ich hab folgende Funktion erstellt:
void read_packet( unsigned char *readbuff, unsigned int length);
ClientSocket1 gibt bei Datenempfang das Paket an die Funktion weiter:
int length = Socket->ReceiveLength(); unsigned char *buffer = (unsigned char*) malloc (length); Socket->ReceiveBuf(buffer,sizeof(buffer)); read_packet(buffer, length);
Die Funktion selbst:
void read_packet(unsigned char *readbuff, unsigned int length) { unsigned int headersize = 4; // Sequence ID lesen und in Form1->Memo1 ausgeben // Gesamtgröße lesen // Anzahl der Wörter lesen // Wörter lesen und in Form1->Memo1 ausgeben (so wie ich das sehe ab dem 12. byte das Pakets) }
Wenn ich das Datenfelde direkt ab dem 12. Byte aus dem Paket auslese und im Memo ausgebe bekomme ich nur Zahlensalat. Normalerweise sollte doch ab dem 12. Byte die Wörter kommen
Die for Schleife habe ich wieder gelöscht weil dies ein vollkommen falscher Lösungsansatz war. Bin ich auf der richtigen Spur oder ist der Ansatz falsch?
Das gesendete Paket und das zu empfangende Paket sind absolut identisch vom Aufbau her
-
So funktioniert TCP/IP nicht. Du kannst nicht davon ausgehen, dass dein komplettes Telegramm mit einem
ReceiveBuf
Aufruf empfangen werden kann. Außerdem hast du noch einen anderen dicken Bock in deinem Code:Socket->ReceiveBuf(buffer,sizeof(buffer));
sizeof(buffer)
liefert 4, dabuffer
ein Zeiger ist und Zeiger nun mal nur 4 Byte im Speicher belegen (zumindest bei Windows 32bit). Du liest also nur 4 Byte, kein Wunder, dass ab Position 12 nix Vernünftiges steht. Auch das Verwenden vonmalloc/free
ist in C++ völlig überflüssig (zumal ich deinem Code nirgendwo einfree
sehe). Deinereceive
Funktion könnte z.B. so aussehen:std::vector<unsigned char> MyClass::receive() { // vector mit entsprechender Empfangsgröße anlegen std::vector<unsigned char> ReceiveBuffer( Socket->ReceiveLength, 0 ); if( !ReceiveBuffer.empty() ) { // Daten in Puffer lesen unsigned int RecvCount = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() ); // vector auf Größe tatsächlich empfangener Bytes bringen ReceiveBuffer.resize( RecvCount ); } return ReceiveBuffer; }
Als nächstes musst du die eingehenden Daten an einen Empfangspuffer anhängen. Jedes Mal, wenn du Daten empfängst musst du Folgende Schritte machen:
- empfangene Daten an Empfangspuffer anhängen
- prüfen, ob mind. 8 Byte im Empfangspuffer stehen (da ab Byte 4 die Gesamttelegrammlänge steht)
- wenn weniger als 8 Byte empfangen worden sind => 9)
- Gesamttelegrammlänge bestimmen
- prüfen, ob entsprechend viele Daten im Empfangspuffer stehen. Wenn nein => 9)
- Telegrammdaten bestimmen und behandeln
- behandelte Telegrammdaten vom Anfang des Empfangspuffers löschen
- => 2)
- auf weitere Daten warten
Dir fehlen offensichtlich noch Grundlagen, insbesondere bei der Verwendung der STL. Fast sämtliche dynamische Speicheranforderungen lassen sich durch Klassen der STL effizienter und robuster realisieren als mit
malloc/free
. Vielleicht solltest du dir ein modernes C++ Buch besorgen und erst ein Mal etwas lesen.
-
Stimmt,jetzt fällt es mir wieder ein. Wenn ich malloc benutze macht es nur Sinn wenn die Funktion jediglich den Pointer auf den allokierten Speicher zurück gibt, abgearbeitet wird und dann anschliessend mit free() freigegeben wird. free() innerhalb der Funktion geht nicht, da nach dem return kein weiterer code abgehandelt wird und davor eine Speicherzugriffsverletzung entstehen würde, weil ein Pointer auf eine Speicheradresse aufgerufen wird die nicht mehr existiert.
Mit Vektoren in diesem Umfang bin ich jetzt zum ersten mal durch dich in Kontakt gekommen und werde mich da fix einlesen. Durch deine Erläuterungen leuchtet mir ein, dass dies ein wirklich gutes Werkzeug zur dynamischen Speicherbelegung ist. Entschuldigt bitte die ein oder andere sehr naive Frage. Hab jetzt seit 6 Jahren zum ersten mal wieder den CBuilder 6 vor Augen und in dieser Zeit scheint sehr vieles auf der Strecke geblieben zu sein. Ich bemühe mich wieder reinzukommen. Vielen Dank für die super Erklärungen und die Starthilfe!!!!
Noch eine Frage
&ReceiveBuffer[0]
0 ist der Index ab dem gelesen werden soll und Receive.Length gibt an bis wohin gelesen werden soll in dem Funktionsaufruf Socket->ReceiveBuf()?
TCP arbeitet ja mit Fehlerkorrektur und deshalb kann es vorkommen das ein nicht richtig übertragenes Paket erneut gesendet wird. Wenn ein Datensatz das TCP Frame in seiner Größe überschreitet, kapselt TCP die Daten in mehrere Pakete. Daher kann ich nicht von ausgehen das alles in einem Paket übertragen wird.
Richtig so?
-
Ich hab nun mal um ne Ausgabe zu bekommen folgendes gemacht (sauber in die Klasse integrieren und Funktionen erstellen mache ich später):
String daten = ""; std::vector<unsigned char> ReceiveBuffer( Socket->ReceiveLength(), 0 ); int recbytes = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() ); if(recbytes > 12) //ab dem 12. byte die wörter { ReceiveBuffer.resize(recbytes); for(int i = 12; i <= recbytes; i++) { daten += ReceiveBuffer[i] ; } ReceiveBuffer.clear(); Memo1->Lines->Add(daten); //Empfangene Daten sequenziell in Memo schreiben }
In Memo1 wird als Serverantwort folgendes ausgegeben:
1400085110107110111119110671111091099711010000Um dies zu decodieren habe ich eine Phyton Funktion gefunden:
def DecodeInt32(data): return unpack('<I', data[0 : 4])[0] def DecodeWords(size, data): numWords = DecodeInt32(data[0:]) words = [] offset = 0 while offset < size: wordLen = DecodeInt32(data[offset : offset + 4]) word = data[offset + 4 : offset + 4 + wordLen] words.append(word) offset += wordLen + 5 return words
Könnte mir bitte jemand helfen den Python Code in C++ zu übersetzen?
-
Nochmal: Dir fehlen Grundlagen. Der Code, den du hier vorgestellt hast, zeigt deutlich, dass du die Problematik nicht vollständig erfasst hast und auch nicht in der Lage bist, eine Lösung umzusetzen. Sich Codeschnipsel aus dem Internet zusammenzusuchen und sich irgendwas zusammenzuschrauben führt in der Regel nicht zum gewünschten Ergebnis. Aber mach dir nix draus, wir haben alle mal angefangen, so ganz auf dem Holzweg bist du nicht
Vielleicht solltest du den Computer einfach mal für ´ne Stunde ausmachen und dir in Ruhe überlegen, was du erreichen willst und wie du das erreichen kannst. Geh im Kopf (und einem Blatt Papier) mal durch, welche Fälle auftreten können und wie man das in den Griff bekommt.
Was passiert denn, wenn bei deinem letzten Code jedes Byte einzeln ankommt?
-
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