Struct variabler Größe



  • struct msg{
       short type;
       struct nutzdaten{
          //daten
       }
    

    Ich will ein Paket per Internet übertragen. Wenn also der Empfänger ein Paket vom typ msg empfängt, soll er in der Lage sein, die Var. type auslesen zu können. Wenn das geschehen ist, weiß er, wie die Nutzdaten aussehen bzw. wie sie zu lesen sind. (Diese Nutzdaten sind aber meist versch. Variablentypen verschiedener Größe).
    Mein Problem: Wie realisiere ich das eigentlich?

    Wenn ich statt "struct nutzdaten" eine union verwende, geht es zwar, ist aber nicht Sinn der Sache, denn ich möchte nicht jedes Mal riesen Pakete durch die Leitung schieben.



  • Einfach kein struct benutzen? Ein struct ist für Kommunikation grundsätzlich ein ganz blöde Idee, weil das Layout im Speicher plattformabhängig ist.



  • TyRoXx schrieb:

    Einfach kein struct benutzen? Ein struct ist für Kommunikation grundsätzlich ein ganz blöde Idee, weil das Layout im Speicher plattformabhängig ist.

    Was wäre denn eine Alternative für mein Problem? Mir fällt nichts ein, was mir da aus Standard C weiterhelfen könnte.



  • Für Netzwerkkommunikation sollte man immer strings nehmen, weil die überall gleich codiert sind.
    sscanf und sprintf sind dein Freund ( pass aber auf Buffer Overflows auf)



  • linux_c89 schrieb:

    Für Netzwerkkommunikation sollte man immer strings nehmen, weil die überall gleich codiert sind.

    Finde ich überhaupt nicht. Ein uint32_t ist auch überall 32 Bit groß.



  • Ein uint32_t ist auch überall 32 Bit groß.

    Es gibt da Unterschiede in Big und Little-Endian.

    Wenn's Binärdaten sind, würde ich das in einen Hexstring wandeln und übertragen,
    vielleicht mit Längenangabe.



  • Scheppertreiber schrieb:

    Ein uint32_t ist auch überall 32 Bit groß.

    Es gibt da Unterschiede in Big und Little-Endian.

    Wenn's Binärdaten sind, würde ich das in einen Hexstring wandeln und übertragen,
    vielleicht mit Längenangabe.

    Daran ist halt unschön, daß Du mit dem Gebinhexe das Datenaufkommen verdoppelst. Weil ich hin und wieder zeitkritische Sachen habe und auch die Konvertierung nicht kostenlos ist, lebe ich lieber mit den Fallstricken, die Structs so haben, als mir ein Monster wie XML zu schultern.

    An Strings störend finde ich die 0- Terminierung.

    Irgendwo hatte ich mal einen Link auf headered Binary- Implementationen, den ich jetzt um's Verrecken nicht finde - für mich war's sowieso oversized. Ich habe meist eine Folge von zwei Structs, die erste gibt Typ, Größe und Checksumme der nachfolgenden an. Die Endianness muß man sowieso beachten, wenn sich Sender und Empfänger da unterscheiden, ein beliebter Stolperstein sind auch die Padding Bytes.
    Wenn man also ein bißchen aufpaßt, kriegt man das mit recht wenig overhead hin.

    Also, trau Dich und teil' das einfach auf zwei Structs auf - einmal Header, einmal Nutzdaten, wobei die Nutzdaten ja durchaus unterschiedlich groß sein dürfen, weil der Client ja weiß, was nach dem Header kommt.



  • Naja, klar. Er will über's Internet übertragen, für Binärdaten
    muß er halt dann das richtige Protokoll verwenden.



  • Ich denke wenn man irgendwie beider Übertragung noch erwähnt ob die übertragenen Daten big- oder little endian sind kann die Gegenstelle das Ganze umwandeln ( geht natürlich nur bei einem selbst definierten Protokoll)
    Dass sich das Datenvolumen vergrößert ist natürlich richtig, da muss man dann halt Prioritäten setzen (Komplexität des Codes und Debuggings vs Datenrate)
    Wenn man keinen besonderen Grund für Binärdaten hat lieber Strings nehmen.



  • linux_c89 schrieb:

    ... ( geht natürlich nur bei einem selbst definierten Protokoll)
    Dass sich das Datenvolumen vergrößert ist natürlich richtig, da muss man dann halt Prioritäten setzen (Komplexität des Codes und Debuggings vs Datenrate)
    Wenn man keinen besonderen Grund für Binärdaten hat lieber Strings nehmen.

    Eher umgekehrt und das Protokoll ist ja erstmal egal. Nehmen wir mal an, er möchte ein UDP- Datagramm zusammenstellen, dann hat er sowieso alles in Händen, dann muß er sich auch nicht damit herumschlagen, alles nach 7 Bit und zurück zu konvertieren. Und im printf() und scanf()- Stall stehen nicht die echten Rennpferde, das Zeug ist echt lahmer Stoff.
    Mit structs geht's eigentlich voll easy:

    void UDPdummy(void *head, void *block)
    {
    }
    
    typedef struct _msg_a_
    {
        int             haensel;
        unsigned int    gretel;
    } msg_a;
    typedef struct _msg_b_
    {
        int hexen;
        int    kuchenhauspreis;
        double hypothekenrate;
        double tilgungsrate;
    } msg_b;
    
    typedef struct _header_
    {
        char            msgtype;
        unsigned int    msglen;
    } msgheader;
    
    void sendsomething(void)
    {
        msgheader header;
        msg_a geschwister;
        msg_b hexenhaus;
        // Hänsel und Gretel in den Wald schicken
        geschwister.haensel = 1;
        geschwister.gretel = 1;
        header.msgtype = 'g';
        header.msglen = sizeof(geschwister);
        UDPdummy(&header, &geschwister);
    
        // Hexenhausdaten schicken
        hexenhaus.hexen = 1;
        hexenhaus.kuchenhauspreis = 30000;
        hexenhaus.hypothekenrate = 148.75;
        hexenhaus.tilgungsrate = 1.05;
        header.msgtype = 'h';
        header.msglen = sizeof(hexenhaus);
        UDPdummy(&header, &hexenhaus);
    }
    

    Das ist wirklich nicht komplex und zum Debuggen auch nicht schlimmer, als einen vergessenen Trenner aus einem Endlos- String zu fischen.
    In den Header kann man natürlich noch was reinschreiben, wie der Datenblock zu interpretieren ist, ich hab's jetzt mal minimalistisch belassen.
    Ein Viewer oder Konverter für solche Daten ist in einer Viertelstunde auch zusammengebastelt, also ich sehe keinen tieferen Sinn darin, alles in einen Stream druckbarer Zeichen und zurück zu konvertieren. 😉



  • Na gut bei UDP würd ich auch Binärdaten verwenden ( wenn ich es mir leisten kann Strings zu benutzen benutz ich auch TCP)


Anmelden zum Antworten