Protokollanleitung als fertiges Paket schreiben



  • 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 und strcpy ab dem ersten nicht mehr weiterkopiert. Ersetz´ den zitierten Code mal durch

    std::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, da buffer 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 von malloc/free ist in C++ völlig überflüssig (zumal ich deinem Code nirgendwo ein free sehe). Deine receive 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:

    1. empfangene Daten an Empfangspuffer anhängen
    2. prüfen, ob mind. 8 Byte im Empfangspuffer stehen (da ab Byte 4 die Gesamttelegrammlänge steht)
    3. wenn weniger als 8 Byte empfangen worden sind => 9)
    4. Gesamttelegrammlänge bestimmen
    5. prüfen, ob entsprechend viele Daten im Empfangspuffer stehen. Wenn nein => 9)
    6. Telegrammdaten bestimmen und behandeln
    7. behandelte Telegrammdaten vom Anfang des Empfangspuffers löschen
    8. => 2)
    9. 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:
    1400085110107110111119110671111091099711010000

    Um 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 ist 😕 Der 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.jpg

    Die 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 einem erase 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.

    1. Stehen genügend Daten bereit für den Telegrammkopf (Sequence ID + Telegrammlänge. Wieviel Bytes haben 2 int32?)? Wenn nein, dann weiter bei 7)
    2. Telegrammlänge aus Bytes 5-8 bestimmen
    3. Stehen genügend Daten für das Telegramm bereit? Wenn nein, dann weiter bei 7)
    4. Behandle die ersten N Bytes des Puffers
    5. Entferne die ersten N Bytes des Puffers
    6. Zurück zu 1)
    7. 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


Anmelden zum Antworten