GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi transtypons-nous sockaddr_in en sockaddr lors de l'appel de bind() ?

Non, ce n'est pas seulement une convention.

sockaddr est un descripteur générique pour tout type d'opération de socket, alors que sockaddr_in est une structure spécifique à la communication basée sur IP (IIRC, "in" signifie "Internet"). A ma connaissance, c'est une sorte de "polymorphisme" :le bind() la fonction fait semblant de prendre un struct sockaddr * , mais en fait, il supposera que le type de structure approprié est transmis ; je. e. celui qui correspond au type de socket que vous lui donnez comme premier argument.


Je ne sais pas si c'est très pertinent pour cette question, mais je voudrais fournir quelques informations supplémentaires qui peuvent rendre la typographie plus compréhensible car beaucoup de gens qui n'ont pas passé beaucoup de temps avec C devenir confus en voyant une telle typographie.

J'utilise macOS , donc je prends des exemples basés sur les fichiers d'en-tête de mon système.

struct sockaddr est défini comme suit :

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 est défini comme suit :

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];
};

À partir des bases, un pointeur contient juste une adresse. Alors struct sockaddr * et struct sockaddr_in * sont à peu près les mêmes. Ils stockent tous les deux une adresse. La seule différence pertinente est la façon dont le compilateur traite ses objets.

Donc, quand vous dites (struct sockaddr *) &name , vous trompez simplement le compilateur et lui dites que cette adresse pointe vers un struct sockaddr saisir.

Supposons donc que le pointeur pointe vers un emplacement 1000 . Si le struct sockaddr * stocke cette adresse, il considérera la mémoire de 1000 à sizeof(struct sockaddr) possédant les membres selon la définition de la structure. Si struct sockaddr_in * stocke la même adresse, il considérera la mémoire de 1000 à sizeof(struct sockaddr_in) .

Lorsque vous avez transtypé ce pointeur, il considérera la même séquence d'octets jusqu'à sizeof(struct sockaddr) .

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

Maintenant, si j'accède à a->sa_len , le compilateur accéderait à partir de l'emplacement 1000 à sizeof(__uint8_t) qui est la même taille en octets que dans le cas de sockaddr_in . Cela devrait donc accéder à la même séquence d'octets.

Le même modèle est pour sa_family .

Après cela, il y a un tableau de caractères de 14 octets dans struct sockaddr qui stocke les données de in_port_t sin_port (typedef 'd entier non signé 16 bits =2 octets ) , struct in_addr sin_addr (simplement une adresse ipv4 32 bits =4 octets) et char sin_zero[8] (8 octets). Ces 3 s'additionnent pour faire 14 octets.

Maintenant, ces trois sont stockés dans ce tableau de caractères de 14 octets et nous pouvons accéder à l'un de ces trois en accédant aux index appropriés et en les transtypant à nouveau.

La réponse de user529758 explique déjà la raison de le faire.


En effet, bind peut lier d'autres types de sockets que les sockets IP, par exemple les sockets de domaine Unix, qui ont sockaddr_un comme type. L'adresse d'un socket AF_INET a l'hôte et le port comme adresse, tandis qu'un socket AF_UNIX a un chemin de système de fichiers.


Linux
  1. Pourquoi OpenStack signale-t-il le type d'hyperviseur comme QEMU alors que libvirt_type est KVM ?

  2. Pourquoi la synchronisation est-elle si importante lors de la création d'une clé USB Linux amorçable ?

  3. Pourquoi la valeur d'inode change lorsque nous éditons dans l'éditeur "vi" ?

  4. Moyen rapide d'inclure un chemin de répertoire lors de l'appel de Mv ? ?

  5. Linux - Pourquoi USB ne fonctionne-t-il pas sous Linux alors qu'il fonctionne sous Uefi/bios ?

Lors de l'utilisation de os.execlp, pourquoi `python` a besoin de `python` comme argv [0]

Pourquoi est-ce que je reçois une autorisation refusée lors de l'exécution de ssh-add ?

Pourquoi ma construction d'Ubuntu est-elle lente lors du déplacement des fenêtres ?

Pourquoi mon montage lié est-il visible en dehors de son espace de noms de montage ?

Pourquoi n'ai-je pas de coloration syntaxique lorsque je sudo vi <filename> ?

Pourquoi Swap est-il utilisé lorsqu'il reste beaucoup de mémoire libre ?