Je sais que sockaddr_in est pour IPv4 et sockaddr_in6 pour IPv6. La confusion pour moi est la différence entre sockaddr et sockaddr_in [6].
Certaines fonctions acceptent sockaddr
et certaines fonctions acceptent sockaddr_in
Ou sockaddr_in6
, Donc:
Et parce que la sizeof(sockaddr_in6) > sizeof(sockaddr) == sizeof(sockaddr_in)
.
Un exemple est: nous avons un socket, et nous voulons en obtenir l'adresse IP de chaîne (elle peut être ipv4 ou ipv6).
Nous appelons d'abord getsockname
pour obtenir un addr
puis appelons inet_ntop
Sur la base de addr.sa_family
.
Y a-t-il un problème avec cet extrait de code?
char ipStr[256];
sockaddr_in6 addr_inv6;
sockaddr* addr = (sockaddr*)&addr_inv6;
sockaddr_in* addr_in = (sockaddr_in*)&addr_inv6;
socklen_t len = sizeof(addr_inv6);
getsockname(_socket, addr, &len);
if (addr->sa_family == AF_INET6) {
inet_ntop(addr_inv6.sin6_family, &addr_inv6.sin6_addr, ipStr, sizeof(ipStr));
// <<<<<<<<IS THIS LINE VALID, getsockname expected a sockaddr, but we use
// it output parameter as sockaddr_in6.
} else {
inet_ntop(addr_in->sin_family, &addr_in->sin_addr, ipStr, sizeof(ipStr));
}
Je ne veux pas répondre à ma question. Mais pour donner plus d'informations ici qui pourraient être utiles à d'autres personnes, je décide de répondre à ma question.
Après Dig dans le code source de linux
. Voici ma conclusion, il existe plusieurs protocoles possibles qui implémentent tous le getsockname
. Et chacun a lui-même une structure de données d'adresse sous-jacente, par exemple, pour IPv4 c'est sockaddr_in
, Et IPV6 sockaddr_in6
Et sockaddr_un
Pour la prise AF_UNIX
. sockaddr
sont utilisés comme support de données commun dans la signature de ces API.
Ces API vont copier socketaddr_in ou sockaddr_in6 ou sockaddr_un sur sockaddr sur la base d'un autre paramètre length
par memcpy.
Et toute la structure de données commence par le même champ de type sa_family.
Sur la base de cette raison, l'extrait de code est valide, car sockaddr_in
Et sockaddr_in6
Ont sa_family
Et nous pouvons ensuite le convertir dans la structure de données appropriée pour une utilisation après vérification sa_family
.
BTY, je ne sais pas pourquoi la sizeof(sockaddr_in6) > sizeof(sockaddr)
, qui cause l'allocation de la base de mémoire sur la taille de sockaddr n'est pas suffisante pour ipv6 (qui est sujette aux erreurs), mais je suppose que c'est pour une raison historique.
sockaddr_in
Et sockaddr_in6
Sont les deux structures où le premier membre est une structure sockaddr
.
Selon la norme C, l'adresse d'une structure et son premier membre sont les mêmes, vous pouvez donc convertir le pointeur en sockaddr_in(6)
en un pointeur en sockaddr
.
Les fonctions prenant sockaddr_in(6)
comme paramètre peuvent modifier la partie sockaddr
, et les fonctions prenant sockaddr
comme paramètre se soucient juste de cette partie.
C'est un peu comme l'héritage.