GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum wandeln wir sockaddr_in in sockaddr um, wenn wir bind() aufrufen?

Nein, es ist nicht nur eine Konvention.

sockaddr ist ein generischer Deskriptor für jede Art von Socket-Operation, während 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, eine struct sockaddr * zu nehmen , aber tatsächlich wird davon ausgegangen, dass der entsprechende Strukturtyp übergeben wird; ich. e. eine, die dem Socket-Typ entspricht, den Sie als erstes Argument angeben.


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 mit C verbracht haben verwirrt werden, wenn man so eine Typisierung sieht.

Ich verwende 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. Also 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.

Wenn Sie also (struct sockaddr *) &name sagen , täuschen Sie nur den Compiler und sagen ihm, dass diese Adresse auf eine struct sockaddr zeigt Typ.

Nehmen wir also an, der Zeiger zeigt auf einen Ort 1000 . Wenn die struct sockaddr * diese Adresse speichert, wird der Speicher von 1000 berücksichtigt bis sizeof(struct sockaddr) Besitz der Mitglieder gemäß der Strukturdefinition. Wenn struct sockaddr_in * speichert die gleiche Adresse, die es als Speicher von 1000 betrachtet bis sizeof(struct sockaddr_in) .

Wenn Sie diesen Zeiger typisiert haben, wird dieselbe Folge von Bytes bis sizeof(struct sockaddr) berücksichtigt .

struct sockaddr *a = &name; // consider &name = 1000

Wenn ich jetzt auf a->sa_len zugreife , würde der Compiler von Speicherort 1000 zugreifen bis sizeof(__uint8_t) das ist dieselbe Bytegröße wie im Fall von sockaddr_in . Dies sollte also auf dieselbe Folge von Bytes zugreifen.

Dasselbe Muster gilt für sa_family .

Danach gibt es in struct sockaddr ein 14-Byte-Zeichenarray die Daten von in_port_t sin_port speichert (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 Bytes). Diese 3 ergeben zusammen 14 Bytes.

Jetzt werden diese drei in diesem 14-Byte-Zeichenarray gespeichert, und wir können auf alle 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.


Linux
  1. Warum meldet OpenStack den Hypervisor-Typ als QEMU, wenn libvirt_type KVM ist?

  2. Warum ändert sich der Inode-Wert, wenn wir im „vi“-Editor bearbeiten?

  3. Warum könnte man ~/.profile zu ~/.bash_profile hinzufügen?

  4. Wann und warum sollte ich Apt-get Update verwenden?

  5. Warum wird mir beim Ausführen von ssh-add die Berechtigung verweigert?

Wann und warum Docker verwendet werden sollte

Warum wird diese Shell-Pipeline beendet?

Warum benötigt `python` bei Verwendung von os.execlp `python` als argv[0]

Warum verzögert sich mein Ubuntu-Build beim Verschieben von Fenstern?

Warum habe ich keine Syntaxhervorhebung, wenn ich sudo vi <Dateiname> drücke?

Warum wird Swap verwendet, wenn noch viel freier Speicher vorhanden ist?