Dynamisches char im struct
-
Erstmal ein ganz großes Dankeschön an jox!!
Leider scheint das mit deinen recvfrom so nicht zu funktionieren, denn es wird nicht ein ankommendes Paket zerlegt, sondern bei jedem recvfrom wird das nächste Paket genommen und davon die sizeof. Somit gehen natürlich alle Daten verloren bis auf die jeweils erste zahl.
Verstehst du was ich meine?
-
... hab ich voll verstanden.
Mit recvfrom() habe ich allerdings auch schon ewig nicht mehr gearbeitet. Ich nehme immer die Grundroutinen (read bzw. write).Überprüf mal, was Deine recvfrom() Aufrufe als Return-Wert zurückgeben (sollte man immer machen ;), etwa:
rc = recvfrom(...); if (rc < 0) { fprintf(stderr,"line=%d, rc=%d, errno=%d (%s)\n",__LINE__,rc,errno,strerror(errno)); }
Ich vermute, dass als Returncode -1 zurückkommt und errno == MSG_TRUNC ist. Was soviel bedeutet, dass wir einen Datagram-Socket haben und der Empfangspuffer zu klein ist.
Nach kurzer Durchsicht der Manual Pages zu recvfrom() nehme ich allerdings an, dass es an der Generierung/Anlage des Sockets liegt. Versuch doch mal:
sockfd = socket(AF_INET,SOCK_STREAM,0);
Mach ich jedenfalls so bei der Server- und der Client-Komponente.
Sonst müssen wir es mir mal mit read() probieren, obwohl ich hier ähnliche Probleme vermute und keine Lösung des Problems sehe.
Wenn Du allerdings die Server-Seite nicht beeinflussen kannst, dann muss man einen anderen Lösungsweg beschreiten. Hierzu müsste ich wissen, ob Du die maximale Größe des Datenpakets kennst.
Doch schau erst einmal, was für ein Returncode zurückkommt.
-
Einen Fehler gibt mein recvfrom nicht zurück. Übrigens fange ich natürlich dort immer die Fehler ab, aber der Code sollte nicht zulang werden. Trotzdem danke für den Hinweis!
read hatte ich schonmal getestet ohne das sich was geändert hat.
Die socket-Methode habe ich auch so schon getestet, ohne Veränderung.Die maximale Größe kenne ich nicht wirklich, aber die Größen bewegen sich im Bereich von 1000-1500. Mehr als 2000 ist es auf jeden Fall nie. Da kann man die Größe ja einfach groß genung wählen z.B. 2000.
Wie das dann aber funktionieren soll weiß ich trotzdem nicht und hoffe da nochmal auf deine Mithilfe. Soweit schonmal vielen Dank!
-
jox schrieb:
recvfrom(s, &test.zahl, sizeof(test.zahl), 0, 0, 0);
man muss den rückgabewert von recv checken. ist der grösser 0 aber kleiner als die ses 'sizeof(test.zahl)' dann wurde nur ein teil empfangen. in diesem fall also recv wiederholt aufrufen bis man alles hat.
-
Der erste Teil (eine Zahl) wird doch auch korrekt empfangen. Gerade das wiederholte aufrufen von recv klappt ja nicht, weil dann das nächste empangene Paket genommen wird und nicht das 'alte' aus dem der Rest gelesen werden soll.
-
germangeek schrieb:
Der erste Teil (eine Zahl) wird doch auch korrekt empfangen. Gerade das wiederholte aufrufen von recv klappt ja nicht, weil dann das nächste empangene Paket genommen wird und nicht das 'alte' aus dem der Rest gelesen werden soll.
dann benutzt du udp (datagramme) und nicht tcp (stream)?
-
jup, ganz genau. Ich hätte nicht erwartet, dass das einen Unterschied macht.
-
germangeek schrieb:
jup, ganz genau. Ich hätte nicht erwartet, dass das einen Unterschied macht.
einen gewaltigen unterschied macht das. tcp schiebt alles empfangene in einen FIFO aus dem der user sich das häppchenweise holen kann. bei udp bekommste pakete und wenn man nicht alles abholt ist der rest weg. guckst du: http://www.c-worker.ch/tuts/udp.html
-
Verdammt! Ich muss an der Stelle leider bei UDP bleiben.
Gibt ess eine Möglichkeit das zu umgehen? Ansonsten hoffe ich ja noch auf jox mit einer genialen Lösung
-
mach ein recv oder recvfrom unter angabe der vollen länge:
unsigned char buffer[1500]; ... recv_result = recv (socket, buffer, sizeof(buffer), 0); ...
dann haste alle daten.
-
Ich bekomme ja nun aber gerade einen struct geschickt! In diesem stehen am Anfang mehrere Zahlen, dann kann ich doch nicht einfach alles in einen char schreiben, oder doch?
-
struct data *test = (struct data*) buffer; printf("Laenge der Daten: %d\n", test->laenge);
-
Da gibt aber den Fehler:
error: dereferencing pointer to incomplete type
-
germangeek schrieb:
Ich bekomme ja nun aber gerade einen struct geschickt! In diesem stehen am Anfang mehrere Zahlen, dann kann ich doch nicht einfach alles in einen char schreiben, oder doch?
Doch, würde ich so auch versuchen. Einfach einen Buffer mit der maximalen Länge vorsehen und dann alles einlesen:
unsigned char buffer[MAX_LENGTH]; struct data *test; rc = recvfrom(s, buffer, sizeof(buffer), 0, 0, 0); test = (struct data *) buffer; if (rc < (sizeof(test->zahl)+sizeof(test->zahl2)+sizeof(test->laenge)) => Error else if (rc != (test->laenge+sizeof(test->zahl)+sizeof(test->zahl2)+sizeof(test->laenge))) => Error else => alles korrekt empfangen ...
Aber Achtung: UDP ist ein ungesichertes Protokoll. Es ist nicht sichergestellt, dass alle Daten rüberkommen! Deswegen der Vergleich: "rc != test->laenge"
-
germangeek schrieb:
Ich bekomme ja nun aber gerade einen struct geschickt! In diesem stehen am Anfang mehrere Zahlen, dann kann ich doch nicht einfach alles in einen char schreiben, oder doch?
das geht (im idealfall so wie lordJax vorschlägt, aber unter vorbehalt, gleicher compiler, gleiche architektur auf beiden seiten usw.). rückgabewert von recv ist dann die paketlänge (also alle struct members und der datenblock)
-
jox schrieb:
Aber Achtung: UDP ist ein ungesichertes Protokoll. Es ist nicht sichergestellt, dass alle Daten rüberkommen! Deswegen der Vergleich: "rc != test->laenge"
nee, wenn das paket ankommt dann ist alles in ordnung. man braucht z.b. keinen crc anhängen oder ähnliches. was passieren kann ist, dass pakete ganz ausbleiben (entweder sie schafften's nicht über's netz oder wurden von lokalen komponenten weggeschmissen wegen negativen integritäts-checks)
-
Okay, dann noch zwei (hoffentlich) letzt Fragen:
1.) Warum gibt es in test = (struct databuffer; den Fehler:
error: incompatible types in assignment
EDIT: 1.) hat sich erledigt. Mein Fehler!
2.) Wie bekomme ich es dann hin, dass meine struktur wieder korrekt ist?
Ich lege mir einen neuen struct data an und kopiere die int's rüber. Wie aber läuft das mit dem char? Das 'echte' char ist ja kleiner als es aktuell im buffer drin liegt!
-
Wieso musst Du die Struct nochmal kopieren? Nimm test, welches auf Buffer zeigt, und gut ist.
Die Daten hinten kannst Du auch mit daten[16] ansprechen, lass Dich nicht davon irritieren, dass die vermeintliche Länge nur 1 ist.
-
germangeek schrieb:
2.) Wie bekomme ich es dann hin, dass meine struktur wieder korrekt ist?
Ich lege mir einen neuen struct data an und kopiere die int's rüber. Wie aber läuft das mit dem char? Das 'echte' char ist ja kleiner als es aktuell im buffer drin liegt!Du brauchst die Strukturelemente nicht zu kopieren, lasse einfach Deine Struktur auf den Anfang des Buffers zeigen (siehe mein Code-Beispiel oben). char[1] ist nur ein "Platzhalter". Du kannst auf die einzelnen Elemente des Array anschließend normal auch mit Indices >0 zugreifen.
-
Wie geben ich denn jetzt z.B. die zahlen aus?
Jetzt bin ich verwirrt...printf("Laenge der Daten: %d\n", test->laenge)
So geht es nämlich nicht.