web-dev-qa-db-ja.com

sockaddr、sockaddr_in、sockaddr_in6の違いは何ですか?

Sockaddr_inはIPv4用で、sockaddr_in6はIPv6用です。私にとって混乱は、sockaddrとsockaddr_in [6]の違いです。

一部の関数はsockaddrを受け入れ、一部の関数は_sockaddr_in_または_sockaddr_in6_を受け入れます。したがって、

  • ルールは何ですか?
  • そして、なぜ2つの異なる構造が必要なのですか?

sizeof(sockaddr_in6) > sizeof(sockaddr) == sizeof(sockaddr_in)であるため。

  • つまり、常にsockaddr_in6を使用してスタック内のメモリを割り当て、ipv4とipv6をサポートする必要がある場合は、sockaddrとsockaddr_inにキャストする必要がありますか?

たとえば、ソケットがあり、そのIPアドレスの文字列IPアドレス(ipv4またはipv6の場合もあります)を取得します。

最初にgetsocknameを呼び出してaddrを取得し、次に_inet_ntop_に基づいて_addr.sa_family_を呼び出します。

このコードスニペットに問題はありますか?

_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));
}
_
41
ZijingWu

質問に答えたくありません。しかし、ここで他の人に役立つかもしれないより多くの情報を提供するために、私の質問に答えることにしました。

linuxのソースコードを調べた後。以下は私の発見です。すべてがgetsocknameを実装する可能性のある複数のプロトコルがあります。そして、それぞれにアドレスデータ構造があります。たとえば、IPv4では_sockaddr_in_、IPV6では_sockaddr_in6_、_sockaddr_un_ソケットでは_AF_UNIX_です。 sockaddrは、これらのAPIの署名の共通データストラットとして使用されます。

これらのAPIは、memcpyによって別のパラメーターlengthに基づいて、socketaddr_inまたはsockaddr_in6またはsockaddr_unをsockaddrにコピーします。

そして、すべてのデータ構造は、同じタイプのフィールドsa_familyで始まります。

これらの理由に基づいて、コードスニペットは有効です。なぜなら、_sockaddr_in_と_sockaddr_in6_の両方に_sa_family_があり、_sa_family_を確認した後、使用するために正しいデータ構造にキャストできるからです。 。

BTY、sockaddrのサイズに基づいてメモリを割り当てるsizeof(sockaddr_in6) > sizeof(sockaddr)がipv6(エラーが発生しやすい)に十分でない理由はわかりませんが、これは履歴上の理由によると思います。

20
ZijingWu

_sockaddr_in_と_sockaddr_in6_は両方とも構造で、最初のメンバーはsockaddr構造です。

C標準によれば、構造体とその最初のメンバーのアドレスは同じであるため、sockaddrへのポインターでsockaddr_in(6)へのポインターをキャストできます。

パラメーターとしてsockaddr_in(6)をとる関数はsockaddr部分を変更する場合があり、パラメーターとしてsockaddrをとる関数はその部分のみを考慮します。

それは少し継承に似ています。

25
linkdd