Struct über Socket senden?
-
Hallo,
ich möchte ein Struct über einen Socket senden. Die Verbindung wurde erfolgreich hergestellt, nur bei der Übertragung weiß ich nicht so recht weiter. Meine Idee war es das komplette Struct nach const char* zu casten, zu übertragen und dann bei Empfänger wieder in das Struct zu casten.
Das struct sieht so aus:
struct Calculation { double number1; double number2; int operation; };
Der code beim Sender:
Calculation calculation = {42, 21, 1}; send(s, (const char*)&calculation, sizeof(calculation), 0);
Und der Code beim Empfänger:
char buf[4096]; //receive recv(connectedSocket,buf,4096,0); printf(buf); printf("\n"); Calculation *calculation = new Calculation; calculation = (Calculation*)&buf; printf("Zahl 1: %d\n", calculation->number1);
Wenn ich den Buffer ausgebe wird nix angezeigt, der scheint also leer zu sein. Dementsprechend wird als Zahl1 auch 0 ausgegeben. Aber wo liegt jetzt der Fehler? Kann man das generell nicht so machen, habe ich es einfach nur falsch gemacht, oder gibt es eine viel bessere Lösung für das Problem?
-
Ich hoffe Calculation hat auch einen konstruktor?
-
AndyK. schrieb:
Ich hoffe Calculation hat auch einen konstruktor?
Ist doch eh ein Memory Leak.
-
AndyK. schrieb:
Ich hoffe Calculation hat auch einen konstruktor?
Calculation ist doch ein struct und braucht keinen Konstruktor?! Oder versteh ich da was falsch?
-
char buf[4096]; //receive recv(connectedSocket,buf,4096,0); printf(buf); printf("\n"); Calculation *calculation = (Calculation*)&buf; printf("Zahl 1: %d\n", calculation->number1);
-
winfer schrieb:
AndyK. schrieb:
Ich hoffe Calculation hat auch einen konstruktor?
Calculation ist doch ein struct und braucht keinen Konstruktor?! Oder versteh ich da was falsch?
Da Du in deinem Code new und Calculation direkt (und nicht etwa mit struct Calculation) verwendest, schliesse ich daraus, dass Du C++ verwendest.
In C++ sind struct und class bis auf die Default Sichtbarkeit der Member gleich.
Hilfe für den Empfangscode:
//receive Calculation calculation = { }; char* buf = reinterpret_cast<char*>(&calculation); recv(connectedSocket,buf,sizeof(calculation),0); printf("Zahl 1: %d\n", calculation.number1);
Edit:
Ausserdem ist noch anzumerken, dass recv(..) einen Return Wert zurückgibt welcher geprüft sein will. Es könnte ein Fehler aufteten (-1) oder die Verbindung wurde getrennt (0) oder nur die Hälfte der Bytes empfangen worden sein (Return Wert ist dann Anzahl empfangene Bytes). Dann wäre dein Calculation struct nur halb gefüllt.
-
Ich habe das jetzt für den receiver mal so übernommen und zusätzlich noch die den Wert abgefragt den recv() zurück gibt. Als Zahl1 wird nach wie vor 0 ausgegeben, der Wert den recv() zurück gibt ist 24. Wenn ich buf als %s ausgebe ist die Ausgabe leer.
-
Calculation calculation = {42, 21, 1}; send(s, (const char*)&calculation, sizeof(calculation), 0); // mach mal: Calculation calculation = {42, 21, 1}; send(s, (const void*)&calculation, sizeof(calculation), 0);
Was ist der Rückgabewert von "send"?
-
Ok, Kommando zurück. Die Lösung von theta funktioniert so wie es da steht. Hatte beim Ausgeben der Zahl ausversehen %d statt %f stehen
Danke für die Hilfe
-
Ich möchte noch eine Warnung am Rande aussprechen:
Versende lieber keine ganzen Strukturen, sondern Member für Member und setze sie beim Empfänger wieder zusammen.Beim binären Senden & Empfangen muss man sowieso schon auf die Endianess acht geben, wenn du dann auch noch auf das Padding und ähnliches aufpassen musst, dann läufst schnell Gefahr Mist zu produzieren
Also die beiden Tipps:
- Immer Member für Member (fundamentale Typen) empfangen und senden.
- Endianess im Hinterkopf behalten.Grüssli
-
Hi
ich weiss das dieser Thread etwas älter ist aber wollte keinen neuen Thread mit einem ähnlichen Titel starten.
Ich möchte einen Objekt(map,methoden) über einem Socket versenden. Auf was sollte geachtet werden? Außerdem funktioniert es wenn man einfach das Objekt mit const char* castet?
Danke im Voraus!
-
J.Wayne schrieb:
Auf was sollte geachtet werden? Außerdem funktioniert es wenn man einfach das Objekt mit const char* castet?
Versende keine Objekte. Kein struct, class oder sonst etwas. Sende alle Member einzeln und setze sie am anderen Ende wieder zusammen. Wenn du "mehrbytige" Zahlen nicht in Text umwandeln möchtest musst du zusätzlich auf die Endianess achten.
-
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 malstd::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 mitstd::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.