Übergeben einer Struktur durch Sockets in C

Lesezeit: 8 Minuten

Benutzeravatar von encodingfreak
Programmierfreak

Ich versuche, die gesamte Struktur vom Client zum Server oder umgekehrt zu übergeben. Nehmen wir meine Struktur wie folgt an

struct temp {
  int a;
  char b;
}

ich benutze senden an und Senden der Adresse der Strukturvariablen und Empfangen auf der anderen Seite unter Verwendung der recvfrom Funktion. Aber ich bin nicht in der Lage, die ursprünglichen Daten zu erhalten, die auf der Empfängerseite gesendet werden. In der sendto-Funktion speichere ich die empfangenen Daten in einer Variablen vom Typ struct temp.

n = sendto(sock, &pkt, sizeof(struct temp), 0, &server, length);
n = recvfrom(sock, &pkt, sizeof(struct temp), 0, (struct sockaddr *)&from,&fromlen);

Wobei pkt die Variable vom Typ struct temp ist.

Ich erhalte zwar 8 Byte Daten, aber wenn ich versuche zu drucken, werden einfach Müllwerte angezeigt. Irgendwelche Hilfe für eine Lösung?

HINWEIS: Es müssen keine Bibliotheken von Drittanbietern verwendet werden.

EDIT1: Ich bin wirklich neu in diesem Serialisierungskonzept. Aber ohne Serialisierung kann ich keine Struktur über Sockets senden?

EDIT2: Wenn ich versuche, eine Zeichenfolge oder eine Integer-Variable mit dem zu senden senden an und recvfrom funktioniert Ich erhalte die Daten auf der Empfängerseite ordnungsgemäß. Warum nicht bei einer Struktur? Wenn ich keine Serialisierungsfunktion verwenden muss, sollte ich dann jedes einzelne Mitglied der Struktur einzeln senden? Dies ist wirklich keine geeignete Lösung, denn wenn es ‘n’ Mitglieder gibt, dann werden ‘n’ Codezeilen hinzugefügt, nur um Daten zu senden oder zu empfangen.

  • Können Sie Ihren Sende-/Empfangscode posten?

    – Brian Agnew

    16. Oktober 2009 um 9:52 Uhr

  • Warum machen Sie meine Änderungen rückgängig, um die seltsamen doppelten Fragezeichen zu korrigieren?

    – abschalten

    16. Oktober 2009 um 12:07 Uhr

  • Verwenden Sie keine Strukturen als Netzwerkprotokolle. Verwenden Sie Netzwerkprotokolle als Netzwerkprotokolle. Entwerfen Sie Ihr Protokoll in Oktetts und schreiben Sie sich eine Bibliothek, um es zu senden und zu empfangen. Oder verwenden Sie eine vorhandene wie DML, XDR, … Die Verwendung von Strukturen führt zu mindestens sechs Abhängigkeiten, die Sie möglicherweise nicht einmal kennen, und verursacht weitere Probleme wie diese.

    – Benutzer207421

    11. Juli 2014 um 21:34 Uhr

  • @EJP – Ich stimme dir zu

    – Programmierfreak

    12. März 2015 um 5:11 Uhr

Benutzeravatar von unwind
entspannen

Das ist eine sehr schlechte Idee. Binäre Daten sollten immer so gesendet werden, dass:

Schreiben Sie niemals eine ganze Struktur binär, nicht in eine Datei, nicht in einen Socket.

Schreiben Sie jedes Feld immer separat und lesen Sie es auf die gleiche Weise.

Sie müssen Funktionen wie haben

unsigned char * serialize_int(unsigned char *buffer, int value)
{
  /* Write big-endian int value into buffer; assumes 32-bit int and 8-bit char. */
  buffer[0] = value >> 24;
  buffer[1] = value >> 16;
  buffer[2] = value >> 8;
  buffer[3] = value;
  return buffer + 4;
}

unsigned char * serialize_char(unsigned char *buffer, char value)
{
  buffer[0] = value;
  return buffer + 1;
}

unsigned char * serialize_temp(unsigned char *buffer, struct temp *value)
{
  buffer = serialize_int(buffer, value->a);
  buffer = serialize_char(buffer, value->b);
  return buffer;
}

unsigned char * deserialize_int(unsigned char *buffer, int *value);

Oder das Äquivalent, es gibt natürlich mehrere Möglichkeiten, dies in Bezug auf die Pufferverwaltung und so weiter einzurichten. Dann müssen Sie die übergeordneten Funktionen ausführen, die ganze Strukturen serialisieren/deserialisieren.

Dies setzt voraus, dass die Serialisierung zu/von Puffern erfolgt, was bedeutet, dass die Serialisierung nicht wissen muss, ob das endgültige Ziel eine Datei oder ein Socket ist. Es bedeutet auch, dass Sie etwas Speicheraufwand bezahlen, aber es ist im Allgemeinen aus Leistungsgründen ein gutes Design (Sie möchten nicht jeden Wert in den Socket schreiben).

Sobald Sie das oben Gesagte haben, können Sie wie folgt eine Strukturinstanz serialisieren und übertragen:

int send_temp(int socket, const struct sockaddr *dest, socklen_t dlen,
              const struct temp *temp)
{
  unsigned char buffer[32], *ptr;

  ptr = serialize_temp(buffer, temp);
  return sendto(socket, buffer, ptr - buffer, 0, dest, dlen) == ptr - buffer;
}

Ein paar Punkte, die zu den oben genannten Punkten zu beachten sind:

  • Die zu sendende Struktur wird zuerst Feld für Feld serialisiert buffer.
  • Die Serialisierungsroutine gibt einen Zeiger auf das nächste freie Byte im Puffer zurück, mit dem wir berechnen, wie viele Bytes es serialisiert hat
  • Offensichtlich schützen meine Beispielserialisierungsroutinen nicht vor Pufferüberlauf.
  • Der Rückgabewert ist 1, wenn die sendto() Aufruf erfolgreich, sonst 0.

  • Und in diesem Fall int können auf den verschiedenen Maschinen auch unterschiedliche Größen haben.

    – Douglas Leder

    16. Oktober 2009 um 9:54 Uhr

  • @Douglas: Absolut wahr und die Liste hinzugefügt. Vielen Dank!

    – abschalten

    16. Oktober 2009 um 9:57 Uhr

  • @unwind – Sind serialize_int und deserialize_int Standardfunktionen?

    – Programmierfreak

    16. Oktober 2009 um 10:00 Uhr

  • @codingfreak: Nein, Sie müssen sie definieren, um die Art der Serialisierung durchzuführen, die Sie benötigen.

    – abschalten

    16. Oktober 2009 um 10:03 Uhr

  • @unwind – Ich habe dich nicht verstanden … ?? Soll ich nur einzelne Mitglieder senden, anstatt die gesamte Struktur auf einmal per Socket zu senden?

    – Programmierfreak

    16. Oktober 2009 um 10:05 Uhr

Die Verwendung der Option „Pragma“ des Pakets hat mein Problem gelöst, aber ich bin mir nicht sicher, ob es irgendwelche Abhängigkeiten gibt.

#pragma pack(1)   // this helps to pack the struct to 5-bytes
struct packet {
int i;
char j;
};
#pragma pack(0)   // turn packing off

Dann funktionierten die folgenden Codezeilen ohne Probleme

n = sendto(sock,&pkt,sizeof(struct packet),0,&server,length);

n = recvfrom(sock, &pkt, sizeof(struct packet), 0, (struct sockaddr *)&from, &fromlen);

Benutzeravatar von qrdl
qrdl

Es müssen keine eigenen Serialisierungsroutinen geschrieben werden short und long Integer-Typen – verwenden htons()/htonl() POSIX-Funktionen.

  • @qrdl: Meine Funktion auch, wie dokumentiert. Es wird immer nach Big-Endian serialisiert. Sie können natürlich auch htonX()/ntohX()-Funktionen verwenden, aber hier wurde versucht, einen allgemeineren Ansatz zu veranschaulichen.

    – abschalten

    16. Oktober 2009 um 11:47 Uhr

  • @codingfreak Ich habe nicht gesagt, es für die Struktur zu verwenden. Es ist der richtige Weg, kurze oder lange Ganzzahlen zu serialisieren, das war’s

    – qrdl

    16. Oktober 2009 um 12:50 Uhr

  • @qrdl – Aber meine Frage ist, wie man eine Struktur über Sockets sendet … auch ohne die Funktionen htons () / htonl () zu verwenden, kann ich Daten mit den Funktionen sendto () und recvfrom () ordnungsgemäß senden und empfangen …. .

    – Programmierfreak

    20. Oktober 2009 um 8:13 Uhr

  • @qrdl: Meine Funktionen setzen nichts über die Endianness des Hosts voraus.

    – abschalten

    20. Oktober 2009 um 10:25 Uhr

  • @unwind Mein Übel. Es tut mir leid, ich vergesse immer wieder, dass Shift Endianness-bewusst ist. Ich werde meinen Beitrag ändern

    – qrdl

    20. Oktober 2009 um 12:11 Uhr

Wenn Sie den Serialisierungscode nicht selbst schreiben möchten, finden Sie ein geeignetes Serialisierungsframework und verwenden Sie dieses.

Vielleicht Googles Protokollpuffer wäre möglich?

Benutzeravatar von eyalm
eyalm

Serialisierung ist eine gute Idee. Sie können auch verwenden Wireshark um den Datenverkehr zu überwachen und zu verstehen, was tatsächlich in den Paketen weitergegeben wird.

Anstatt zu serialisieren und von Bibliotheken von Drittanbietern abhängig zu sein, ist es einfach, ein primitives Protokoll mit Tag, Länge und Wert zu erstellen.

Tag: 32 bit value identifying the field
Length: 32 bit value specifying the length in bytes of the field
Value: the field

Verketten Sie nach Bedarf. Verwenden Sie Aufzählungen für die Tags. Und verwenden Sie die Netzwerk-Byte-Reihenfolge …

Einfach zu codieren, einfach zu decodieren.

Auch wenn Sie TCP verwenden, denken Sie daran, dass es a ist Strom von Daten, wenn Sie also zB 3 Pakete senden, werden Sie nicht unbedingt 3 Pakete empfangen. Sie können unter anderem abhängig vom Nodelay / Nagel-Algorithmus in einen Stream “zusammengeführt” werden, und Sie können sie alle in einem Recv erhalten … Sie müssen die Daten beispielsweise mit RFC1006 begrenzen.

UDP ist einfacher, Sie erhalten für jedes gesendete Paket ein eigenes Paket, aber es ist viel weniger sicher.

Benutzeravatar von the_mandrill
der_mandrill

Wenn das Format der Daten, die Sie übertragen möchten, sehr einfach ist, dann ist die Konvertierung in und aus einer ANSI-Zeichenfolge einfach und portabel.

  • @mandrill – Nehmen wir an, es ist komplex —- eine generische Lösung wäre die beste Antwort, wenn möglich … ??

    – Programmierfreak

    16. Oktober 2009 um 12:35 Uhr

  • Wenn das Format komplexer ist, verweise ich auf die überlegenen Lösungen, die an anderer Stelle in diesem Thread angegeben sind! Alternativ zu etwas allgemeinerem wie XML oder einem SOAP-ähnlichen Wrapper serialisieren.

    – der_Mandrill

    16. Oktober 2009 um 15:28 Uhr

  • Letztendlich besteht das Ziel darin, Ihre Daten portabel zu serialisieren, sodass die Konvertierung in und aus einer Zeichenfolge portabel, einfach und lesbar ist. Dies ist möglicherweise nicht die sicherste oder effizienteste Methode, erfordert jedoch keine Bibliotheken von Drittanbietern.

    – der_Mandrill

    16. Oktober 2009 um 15:31 Uhr

  • Wie konvertiere ich die Zeichenfolge wieder in die Daten, die in eine Struktur eingefügt werden können …. es wäre komplexer, denke ich?

    – Programmierfreak

    17. Oktober 2009 um 13:45 Uhr

  • Um die Zeichenfolge wieder in Daten umzuwandeln, müssten Sie die Zeichenfolge analysieren, indem Sie Dinge wie atof(), atoi(), sscanf() usw. verwenden (na ja, vielleicht nicht sscanf(), es ist gefährlich). Sie haben Recht, das Analysieren der Zeichenfolge kann für nicht einfache Daten komplex werden. Ich würde stattdessen die Verwendung einer Serialisierungsbibliothek eines Drittanbieters empfehlen.

    – Jeremy Friesner

    17. Oktober 2009 um 17:14 Uhr

1412380cookie-checkÜbergeben einer Struktur durch Sockets in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy