remote steuerung



  • was is das beste design wenn man ein programm remote steuern will
    also zweimal dasselbe programm mit 100+ einzelbefehlen

    mir gehts vorallem darum wie ich codezeilen sparen kann ohne für
    jede funktion ein struct zu schreiben, ein riesenstructs für alle
    funktionen zu verwenden oder es unübersichtlich werden zu lassen

    pseudobeispiel:
    
    //funktion die remote aufgerufen werden soll
    long function ( long lParam, long* lReturn );
    
    //struct um die parameter und das ergebnis der funktion zu übertragen
    struct cFunction
    {
      long lResult;
      long lParam;
      long lReturn;
    };
    
    //send
    cFunction f;
    socket.send ( f, sizeof(f) );
    
    //receive
    cFunction f;
    socket.receive ( &f );
    
    //call
    f.lResult = function ( f.lParam, &f.lReturn );
    
    //reply
    socket.send ( f, sizeof(f) );
    


  • Sovok schrieb:

    mir gehts vorallem darum wie ich codezeilen sparen kann ohne für
    jede funktion ein struct zu schreiben, ein riesenstructs für alle
    funktionen zu verwenden oder es unübersichtlich werden zu lassen

    Deine Bedingungen schliessen sich doch gegenseitig aus.

    Ich würde eine Basisklasse "Befehl" machen, die erstmal nur einen "Befehlscode" (z.b int) enthält. Davon leitest man dann die wirklichen Befehle ab. Beim übertragen werden zunächst nur die ersten 4 byte (= der int) betrachet und dann das Datenpacket in den passenen Typ gecastet. Dann gibt es einfach eine execute Methode im Befehl, der diesen ausführt. Für jeden Befehl überschreiben, fertig. Kein Riesenstruct, übersichtlich, aber eben für jedes ein struct/class.

    Bye, TGGC (Denken, und gut ist.)



  • TGGC schrieb:

    Sovok schrieb:

    mir gehts vorallem darum wie ich codezeilen sparen kann ohne für
    jede funktion ein struct zu schreiben, ein riesenstructs für alle
    funktionen zu verwenden oder es unübersichtlich werden zu lassen

    Deine Bedingungen schliessen sich doch gegenseitig aus.

    Ich würde eine Basisklasse "Befehl" machen, die erstmal nur einen "Befehlscode" (z.b int) enthält. Davon leitest man dann die wirklichen Befehle ab. Beim übertragen werden zunächst nur die ersten 4 byte (= der int) betrachet und dann das Datenpacket in den passenen Typ gecastet. Dann gibt es einfach eine execute Methode im Befehl, der diesen ausführt. Für jeden Befehl überschreiben, fertig. Kein Riesenstruct, übersichtlich, aber eben für jedes ein struct/class.

    Bye, TGGC (Denken, und gut ist.)

    natürlich schliessen sie sich gegenseitig aus wenn mans extrem umsetzt
    ich such halt den besten mittelweg

    deine idee is schonmal gut

    muss ich noch irgendwas beachten bei memory operationen mit klassen ausser, dass das sizeof auf nen basisklassenpointer nicht die gesamtgrösse ergibt?



  • Auch wann das eher nicht zu C++ gehört: Warum nicht DCOM, XML-RPC, Corba und Co.?
    Ich hab bisher nur DCOM selber eigesetzt, weil man damit eine verteilte Anwendung richtig schön als ein großes ganzes basteln kann.



  • TheBigW schrieb:

    Auch wann das eher nicht zu C++ gehört: Warum nicht DCOM, XML-RPC, Corba und Co.?
    Ich hab bisher nur DCOM selber eigesetzt, weil man damit eine verteilte Anwendung richtig schön als ein großes ganzes basteln kann.

    ich nehm mal an du hast die schon benutzt

    welche vorraussetzungen müssen gegeben sein?
    betriebssystem/os-features

    die software läuft auch auf single threaded systemen mit sparsamen c++ support (keine exceptions/keine standard template library)



  • Sovok schrieb:

    muss ich noch irgendwas beachten bei memory operationen mit klassen ausser, dass das sizeof auf nen basisklassenpointer nicht die gesamtgrösse ergibt?

    Wäre besser, keine virtuellen Methoden zu benutzen, sonst kommen 4(?) Byte dazu. 1 Byte Alignment kann auch sinnvoll sein.

    Bye, TGGC (Denken, und gut ist.)



  • Sovok schrieb:

    TheBigW schrieb:

    Auch wann das eher nicht zu C++ gehört: Warum nicht DCOM, XML-RPC, Corba und Co.?
    Ich hab bisher nur DCOM selber eigesetzt, weil man damit eine verteilte Anwendung richtig schön als ein großes ganzes basteln kann.

    ich nehm mal an du hast die schon benutzt

    welche vorraussetzungen müssen gegeben sein?
    betriebssystem/os-features

    die software läuft auch auf single threaded systemen mit sparsamen c++ support (keine exceptions/keine standard template library)

    DCOM erwartet Windows und ist Microsoft spezifisch
    *XML-RPC ist ein RPC Protokoll, dass XML zur Kommunikation nutzt *yuck
    Ist aber Plattform- und Sprach-unabhängig
    *CORBA ist auch Plattform-/Sprach-unabhängig, aber bringt auch einiges an Komplexität mit (siehe ACE)



  • 1 Byte Alignment kann auch sinnvoll sein.

    byte alignment kenn ich nur von structs... hoffe das funktioniert reibungslos mit klassen

    Wäre besser, keine virtuellen Methoden zu benutzen, sonst kommen 4(?) Byte dazu

    kommen ausser dem grösenunterschied noch weitere probleme mit virtuellen methoden hinzu?

    was passiert wenn ich die virtuelle execute methode einbau, die instanz mit sizeof(abgeleitet) per socket verschick

    dann auf der anderen seite den datenpointer in baseclass caste und execute aufrufe?

    wird dann die implementierung der abgeleiteten aufgerufen oder stimmen nach dem transport die daten der instanz nicht mehr?

    noch was anderes... wer kümmert sich um die anordnung der daten?
    z.b. host(win32): little endian <-> client(linux): big endian



  • noch was anderes... wer kümmert sich um die anordnung der daten?
    z.b. host(win32): little endian <-> client(linux): big endian

    der client kümmert sich drum



  • dann auf der anderen seite den datenpointer in baseclass caste und execute aufrufe?

    Das funktioniert, wenn der Code auf beiden Seiten Binär kompatibel ist und die Implementation der Derived Klasse gleich zur Verfügung stehen (sind alles sehr schwierig einzuhaltende Bedingungen!), sollte alles gut gehen. Ansonsten hast du eben einen kaputten vtable und die daraus folgenden Erscheinungen.

    Ich würde aber eher sagen, dass das nicht klappt.

    Serialisiere einfach vernünftig und schicke keine Binärenklassen! Oder nimm ein existierendes RPC Protokoll (CORBA etc.)

    sizeof auf einen Pointer liefert übrigens die größe des Pointer-Typs 🙄

    noch was anderes... wer kümmert sich um die anordnung der daten?
    z.b. host(win32): little endian <-> client(linux): big endian

    *bumm* Deine Lösung wird so nicht gehen, wenn ich das sehe.

    Aber zu der Frage. Wer sich darum kümmert: Niemand, darum muss sich dein Protokoll kümmern (bzw. dessen Implementierung)



  • Serialisiere einfach vernünftig und schicke keine Binärenklassen!

    was verstehts du unter vernünftig?

    sizeof auf einen Pointer liefert übrigens die größe des Pointer-Typs 🙄

    jaja natürlich sizeof((abgeleitet)pBase);

    noch was anderes... wer kümmert sich um die anordnung der daten?
    z.b. host(win32): little endian <-> client(linux): big endian

    *bumm* Deine Lösung wird so nicht gehen, wenn ich das sehe.

    Aber zu der Frage. Wer sich darum kümmert: Niemand, darum muss sich dein Protokoll kümmern (bzw. dessen Implementierung)

    kümmern sich XML-RPC und CORBA um sowas?



  • Sovok schrieb:

    was verstehts du unter vernünftig?

    Das eben nur der Befehlscode und die Parameter (am besten noch in definiertem Encoding) geschickt werden, statt einfach nur send( &class );

    Bye, TGGC (Dem beste BdT)



  • am besten noch in definiertem Encoding

    wie ist ein definiertes Encoding richtig implementiert?

    ansonsten würd ich halt nen buffer erstellen mit den ersten 4 bytes als id
    und dann per template funktion die restlichen werte dranhängen

    beim empfangen dann halt ein bischen pointerarithmetik a la

    unsigned char* buffer;
    m_lval1 = *(long*)buffer;
    buffer += sizeof ( m_lval1 );
    m_ival1 = *(int*)buffer;
    

    ...ach du sch*****
    was mach ich dann wenn sich die grösse der datentypen ändert
    z.b. long auf dem host 32bit und auf dem client 40bit

    sollte ich die werte sämtlicher kommandoparameter per typedef auf ne bestimmte grösse setzen und dann die typedefs je nach plattform ändern?

    ekelhaft is vorallem sowas

    //32bit in 40bit variable schreiben
    m_lval1 = *(long*)buffer;
    
    //hab schon lang nich mehr geshiftet aber is des richtig?
    m_lval1 = *(long*)buffer >> 8 ;
    


  • ...ach du sch*****
    was mach ich dann wenn sich die grösse der datentypen ändert
    z.b. long auf dem host 32bit und auf dem client 40bit

    sollte ich die werte sämtlicher kommandoparameter per typedef auf ne bestimmte grösse setzen und dann die typedefs je nach plattform ändern?

    Ja, genau das sind die Probleme von Binär Sachen. Alignment kommt da wie bereits gesagt auch noch hinzu.

    Schau dir am besten mal an, wie XML-RPC arbeitet. Du musst ja nicht unbedingt XML für das Protokoll nehmen.



  • Sovok schrieb:

    was mach ich dann wenn sich die grösse der datentypen ändert
    z.b. long auf dem host 32bit und auf dem client 40bit

    Genau sowas: man schickt nicht so, wie es grad im Speicehr steht. Wenn es mit allen mmöglichen Maschinen gehen soll, dann legst du fest, das die Übertragung z.b. big endian und int = 32 Bit sind. Jeder der sendet und empfängt muss dann evtl. konvertieren.

    Bye, TGGC (Dem beste BdT)



  • ok wie wärs mit

    <ID>(4byte)<LF>
    <DATATYPE><DATA><LF>
    <DATATYPE><DATA><LF>
    <DATATYPE><DATA><LF>
    ...
    ...
    <CRLF>

    //CR == \r LF == \n

    als DATATYPE gibts
    32bit ganzzahl,
    64bit fliesskomma,
    8bit char,
    unbestimmte länge string

    reihenfolge little endian

    beim schreiben müssen die datentypen in die jeweiligen längen gepresst werden und beim lesen darf nur die jeweilige länge gelesen werden

    hab ich was übersehn?

    was heisst eigentlich network byte order in der praxis...
    hab das irgendwo aufgeschnappt



  • Wenn die Strings nullterminiert sind, kannst du die LF streichen. Die ID sollte die Datentypen und deren Anzahl bestimmen, solange keine variablen Parameter (wie printf) nötig sind: Datatype und crlf streichen. Diese beiden Zeichen (cr/lf) können sowieso überall in den Daten auftreten.

    Bye, TGGC (Dem beste BdT)



  • TGGC schrieb:

    Wenn die Strings nullterminiert sind, kannst du die LF streichen. Die ID sollte die Datentypen und deren Anzahl bestimmen, solange keine variablen Parameter (wie printf) nötig sind: Datatype und crlf streichen. Diese beiden Zeichen (cr/lf) können sowieso überall in den Daten auftreten.

    Bye, TGGC (Dem beste BdT)

    stimmt hast recht

    also
    <ID>(4byte)<DATA><DATA><DATA><DATA>...

    wie siehts mit unicode strings aus
    werden die auch mit \0 terminiert?



  • kümmern sich XML-RPC und CORBA um sowas?

    Jep. Leider kann ich es nur für DCOM halbwegs erklären. Microsoft definiert einfach eigene Datentypen in der IDL, die dann je nach Zielsystem übersetzt werden. Das nimmt Dir somit die arbeit ab, Dich um sowas zu kümmern. Sonst würde es ja nie funktionieren den Server in C++ zu schreiben und die Clients dann mit z.B. VB einzubinden.
    Im Prinzip arbeiten alle diese RPC Lösungen IMHO ähnlich. Der "Übersetzungsaufwand" zwischen den Systemen wird Dir suzusagen abgenommen. Ich glaube mich düster zu erinnern, das das irgendwie Marshalling, oder so ähnlich genannt wird.

    Aber Dein Ansatz, sowas selbst zu basteln gefällt mir auch ganz gut 👍 .

    Wenn ich mich recht entsinne sind unicode strings auch \0 terminiert.


Anmelden zum Antworten