Das binden() Die Funktion akzeptiert einen Zeiger auf a sockaddr
aber in allen Beispielen, die ich gesehen habe, a sockaddr_in
stattdessen wird eine Struktur verwendet, in die gecastet wird sockaddr
:
struct sockaddr_in name;
...
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
...
Ich kann mir nicht vorstellen, warum a ist sockaddr_in
Struktur verwendet. Warum nicht einfach vorbereiten und passieren a sockaddr
?
Ist es nur Konvention?
Nein, es ist nicht nur Konvention.
sockaddr
ist ein generischer Deskriptor für jede Art von Socket-Operation, wohingegen sockaddr_in
ist eine spezifische Struktur für die IP-basierte Kommunikation (IIRC, „in“ steht für „Internet“). Soweit ich weiß, ist dies eine Art “Polymorphismus”: die bind()
Funktion gibt vor, a zu nehmen struct sockaddr *
, aber tatsächlich wird davon ausgegangen, dass der entsprechende Strukturtyp übergeben wird; dh eine, die dem Socket-Typ entspricht, den Sie ihm als erstes Argument geben.
Ich weiß nicht, ob es für diese Frage sehr relevant ist, aber ich möchte einige zusätzliche Informationen bereitstellen, die die Typisierung für viele Menschen verständlicher machen, die nicht viel Zeit damit verbracht haben C
verwirrt werden, wenn man eine solche Typisierung sieht.
ich benutze macOS
also nehme ich Beispiele basierend auf Header-Dateien von meinem System.
struct sockaddr
ist wie folgt definiert:
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
struct sockaddr_in
ist wie folgt definiert:
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Ausgehend von den Grundlagen enthält ein Zeiger nur eine Adresse. So struct sockaddr *
und struct sockaddr_in *
sind ziemlich gleich. Beide speichern nur eine Adresse. Der einzige relevante Unterschied besteht darin, wie der Compiler seine Objekte behandelt.
Also wenn du sagst (struct sockaddr *) &name
täuschen Sie nur den Compiler und sagen ihm, dass diese Adresse auf a zeigt struct sockaddr
Typ.
Nehmen wir also an, der Zeiger zeigt auf einen Ort 1000
. Wenn die struct sockaddr *
speichert diese Adresse, wird es Speicher aus berücksichtigen 1000
zu sizeof(struct sockaddr)
Besitz der Mitglieder gemäß der Strukturdefinition. Wenn struct sockaddr_in *
speichert die gleiche Adresse, von der es den Speicher berücksichtigt 1000
zu sizeof(struct sockaddr_in)
.
Wenn Sie diesen Zeiger typisiert haben, wird dieselbe Folge von Bytes bis zu berücksichtigt sizeof(struct sockaddr)
.
struct sockaddr *a = &name; // consider &name = 1000
Wenn ich jetzt zugreife a->sa_len
würde der Compiler von Ort aus zugreifen 1000
zu sizeof(__uint8_t)
das ist die gleiche Bytegröße wie im Fall von sockaddr_in
. Dies sollte also auf dieselbe Folge von Bytes zugreifen.
Das gleiche Muster ist für sa_family
.
Danach gibt es ein 14-Byte-Zeichen-Array struct sockaddr
die Daten von speichert in_port_t sin_port
(typedef
‘d 16-Bit-Ganzzahl ohne Vorzeichen = 2 Bytes ), struct in_addr sin_addr
(einfach eine 32-Bit-IPv4-Adresse = 4 Bytes) und char sin_zero[8]
(8 Byte). Diese 3 ergeben zusammen 14 Bytes.
Jetzt werden diese drei in diesem 14-Byte-Zeichenarray gespeichert, und wir können auf alle diese drei zugreifen, indem wir auf die entsprechenden Indizes zugreifen und sie erneut typisieren.
Die Antwort von user529758 erklärt bereits den Grund dafür.
Dies liegt daran, dass bind andere Arten von Sockets als IP-Sockets binden kann, zum Beispiel Unix-Domain-Sockets, die sockaddr_un als Typ haben. Die Adresse für einen AF_INET-Socket hat den Host und den Port als Adresse, während ein AF_UNIX-Socket einen Dateisystempfad hat.
NB.
sockaddr_in6
existiert auch, und jeder, der neuen Code schreibt, wäre gut beraten, ihn einzufügen …– BRPocock
13. Januar 2014 um 19:00 Uhr
Sie haben einen sehr wichtigen Teil in Ihrem Code ausgelassen:
name.sa_family = AF_INET
zumstruct sockaddr_in
! In Betracht ziehenstruct sockaddr
eine Vereinigung aller anderen sockaddr-Typen sein. Die einzige Gemeinsamkeit ist, dass sie ein erstes Mitglied habensa_family_t sa_family
die dem tatsächlichen Strukturtyp entsprechen müssen.– Ulrich Eckhardt
25. Januar 2015 um 10:47 Uhr