Struct über Socket senden?



  • kannst du mir vielleicht noch Licht ins dunkle bringen und mir sagen warum ich nicht komplette Objekte versenden soll?

    Danke



  • Es hängt halt ganz vom Objekt ab, ob es versendbar ist oder nicht. PODs (Plain Old Data) lassen sich über´s Netzwerk problemlos verschicken, aber komplexe Objekte (solche, die z.B. std::string oder std::vector oder Ähnliches enthalten) erfordern etwas mehr Aufwand.
    Der Grund dafür ist ziemlich simpel: Die Daten eines PODs liegen linear im Speicher, das Objekt belegt einen zusammenhängenden Speicherblock. Dieser Block lässt sich ohne Probleme übers Netzwerk verschicken, da alle Daten in diesem Block enthalten sind.
    Bei komplexen Objekten ist das eher die Ausnahme, nehmen wir als Beispiel mal std::string . Dort ist die interne Repräsentation der Daten nicht bekannt, sie könnte z.B. aus drei Zeigern bestehen (Zeiger auf Blockanfang, Zeiger auf Stringende, Zeiger auf Blockende). Wenn du jetzt den String mit

    std::string peng;
    
    send( socket, &peng, sizeof( std::string ),0 )
    

    verschickst dann sendest du lediglich die drei Zeiger über´s Netzwerk, nicht aber den Stringinhalt. Auf der Gegenstelle werden drei Zeiger empfangen, die in´s Nirvana zeigen und beim Zugriff UB auslösen.



  • > PODs (Plain Old Data) lassen sich über´s Netzwerk problemlos verschicken,

    Das glaube ich nicht. Wie Dravere damals schon sagte, kann es da durchaus Probleme mit der Byte-Reihenfolge und dem Alignment bei unterschiedlichen Systemen geben. Besser, man benutzt ein kleines Anwendungsprotokoll (wie JSON).



  • Ok danke dir für die Erklärung.

    ich habe so etwas implemtiert und möchte es auf der Gegenseite wieder empfangen.

    #include <iostream>
    #include <map>
    #include <sstream>
    
    class Beispiel{
    		private:
    		std::map<int,std::string> map1;
    
            public:
    		template<typename T>
    		void bla(int bla, T value);
    
    		template<typename T>
    		T blubb(int blubbVariable);
    		Beispiel(){
    		}
    };
    

    Nun habe ich ein Objekt angelegt und habe Versucht so etwas zu machen:

    Beispiel *bsp = new Beispiel();
    rc=send(s,(const char*)bsp,sizeof(comProtocol),0);
    

    Wie kann man dies übertragen bzw mit recv empfangen?



  • J.Wayne schrieb:

    Wie kann man dies übertragen bzw mit recv empfangen?

    Nein, so hast du keine Chance. Wie DocShoe schon sagte, std::string/std::map fordern Speicher auf dem Heap an, du würdest nur Pointer verschicken. Du musst die Kompontenten auflösen und einzeln senden.

    @DocShoe Dank Padding sollte man das auch bei "flachen" Structs so machen, auch wenn man natürlich Glück haben kann und es funktioniert. Aber man weiß ja nie. 🙂



  • J.Wayne schrieb:

    ...

    Ich bin froh, dass du die Antworten der anderen durchgelesen hast...

    Im ernst, du hast genau nichts davon getan, was die anderen dir geraten haben!
    Schalte dein Hirn ein und lies von vorne.



  • Meinem Vorredner sollte ich nicht antworten aber ich konnte mich nicht zurückhalten. Es ist halt nicht jeder ein Programmierking und deswegen existieren auch solche Foren um Fragen zu stellen. Falls du auf die Fragen nicht eingehen möchtest, behalte deine Meinung für dich.

    Danke dir cooky451 und natürlich auch DocShoe, für die ausführliche Beschreibung.

    Mal schauen wie ich das jetzt versende :S



  • Jodocus schrieb:

    > PODs (Plain Old Data) lassen sich über´s Netzwerk problemlos verschicken,

    Das glaube ich nicht. Wie Dravere damals schon sagte, kann es da durchaus Probleme mit der Byte-Reihenfolge und dem Alignment bei unterschiedlichen Systemen geben. Besser, man benutzt ein kleines Anwendungsprotokoll (wie JSON).

    Wenn man für mehrere Plattformen entwickelt gebe ich dir recht, aber die meisten Hobby-/Amateurprogrammierer tun das wohl nicht und daher bin ich auf diesen Punkt nicht eingegangen.



  • Ich wollte mich nochmals melden. Ist es möglich das Object als char* umzuwandeln und dies dann über einen Socket zu versenden oder entsteht dabei, dass von euch angesprochene Zeigerproblem mit string-Typen?

    Ich brauch definitiv eine Lösung für die Versendung der Daten. Wie würdet ihr das Objekt(Programmcode s. oben) versenden?

    Grüße



  • Das kommt ganz darauf an, was du unter "zu char* umzuwandeln" verstehst. Ein einfacher Cast reicht definitiv nicht aus, da hast du die bereits angesprochenen Probleme. Aber du kannst das Objekt in eine zusammenhängende Textdarstellung formatieren, die dann gesendet werden kann (die Gegenseite muß dieses Format dann kennen und parsen, um daraus wieder das Objekt zu rekonstruieren):

    std::istringstream data;
    data<<map1.size()<<'\n';
    for(auto it=map1.begin();it!=map1.end();++it)
      data<<it->first<<'\t'<<it->second<<'\n';
    std::string text=data.str();
    send(text.c_str());
    


  • Ich meinte auch mit "zu char* umzuwandeln" einen cast auf char*. Ich habe gehofft, dass ein einfacher Cast möglich ist aber Pusstekuchen.

    ich werde versuchen das irgendwie doch noch auf die Beine zubekommen 😉

    Danke



  • ich hätte da noch eine Frage die ich gerne loswerden möchte.
    was macht den bitte dieser Codeabschnitt:

    for(auto it=map1.begin();it!=map1.end();++it)
      data<<it->first<<'\t'<<it->second<<'\n';
    

    bei mir wird ein Fehler ausgegeben. Vielleicht sollte ich erwähnen, dass ich mit Visual Studio 2008 programmiere bzw unter Windows.



  • Praktisch gesehen iteriert er über die map<> und packt alle Elemente in den Hilfsstream. Das "auto" könnte allerdings ein Problem sein für Compiler, die noch kein C++0x unterstützen - das mußt du im Zweifelsfall ersetzen durch "map<int,string>::iterator".

    (PS: "bei mir wird ein Fehler ausgegeben" ist eine sehr präzise Beschreibung des Problems ;))



  • jepp es lag am "auto". Ich habe es gerade mit einem Iterator durchlaufen lassen und siehe da kein Fehler. Der Fehler war irgendwie eine halbe Seite lang und ich wollte hier kein Spam verursachen 🙂

    puh der erste Schritt wurde durchgeführt nun folgt der Rest 🙂

    wie kann ich jetzt aus dieser wieder ein map Eintrag machen?
    bräuchte wieder ein

    map<int,string>
    

    wahrscheinlich müsste ich die Nachricht in einer for-Schleife durchlaufen und die einzelnen Werte jeweils in die Map einfügen nehme ich mal schwer an 😃



  • J.Wayne schrieb:

    jepp es lag am "auto". Ich habe es gerade mit einem Iterator durchlaufen lassen und siehe da kein Fehler. Der Fehler war irgendwie eine halbe Seite lang und ich wollte hier kein Spam verursachen 🙂

    puh der erste Schritt wurde durchgeführt nun folgt der Rest 🙂

    wie kann ich jetzt aus dieser wieder ein map Eintrag machen?
    bräuchte wieder ein

    map<int,string>
    

    wahrscheinlich müsste ich die Nachricht in einer for-Schleife durchlaufen und die einzelnen Werte jeweils in die Map einfügen nehme ich mal schwer an 😃

    Edit: wie groß soll bei

    rc=recv(connectedSocket,buf,sizeof(MapStruct),0);
    

    als size angeben?



  • Wie ich schon oben gesagt habe: Beim Empfangen dieser Daten mußt du den String wieder parsen. Dazu hatte ich oben schon ein paar Trennzeichen eingefügt, an denen du dich orientieren kannst (ich würde wieder einen Stringstream verwenden und die Daten per >> und getline() rausholen - aber ich hab' keine Lust, dir jetzt alles vorzukauen).

    PS: Was die Größe angeht: Hol dir alles was kommt (blockweise in einer Schleife, bis recv() -1 angibt) und lager es in einem String zwischen, der dann verarbeitet wird:

    char buf[XYZ+1];//Größe ist afaik unwichtig, muß nur bekannt sein
    string recieved;
    int count;
    while((count = recieve(socket,buf,XYZ))>=0)
    {
      buf[count]='\0';
      recieved+=buf;
    }
    ...
    


  • ich muss nochmals kurz stören. Es läuft alles wunderbar bis auf die Schleife für den Datenempfang. Das Programm ist in dieser Schleife und kommt nicht mehr heraus, ergo er ist in einer Enlosschleife gefangen. 😕

    Eine alternative fällt mir nicht ein. Habe einige Methoden versucht aber passt nicht. Ich könnte den array für size-Wert hoch wählen, aber dies wäre eine statische Lsg. Vielleicht fällt jemanden noch etwas ein.



  • Ändere >= in > 0



  • Ich hätte bezüglich String parsen eine Frage:

    würde dieser Codeabschnitt eventuell Sinn machen

    stringstream data; 
    string key;
    while(data>>key)
    	cout<<key.c_str();
    

    Meine Frage ist aus Performansgründen oder programmiertechnisch für einen sauberen Code. Die meisten kennen sich besser aus als ich 🙂

    @cooky451 wurde schon ausprobiert aber war erfolglos 😕


Anmelden zum Antworten