sockaddr,sockaddr_in和sockaddr_in6有什么区别?

Zij*_*gWu 42 c c++ api network-programming

我知道sockaddr_in用于IPv4,sockaddr_in6用于IPv6.我的困惑是sockaddr和sockaddr_in之间的区别[6].

有些函数接受sockaddr,有些函数接受sockaddr_insockaddr_in6,所以:

  • 规则是什么?
  • 为什么需要两种不同的结构?

而且因为sizeof(sockaddr_in6) > sizeof(sockaddr) == sizeof(sockaddr_in).

  • 这是否意味着如果我们需要支持ipv4和ipv6,我们应该总是使用sockaddr_in6在堆栈中分配内存并转换为sockaddr和sockaddr_in?

一个例子是:我们有一个套接字,我们想得到它的字符串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));
}
Run Code Online (Sandbox Code Playgroud)

lin*_*kdd 25

sockaddr_in并且sockaddr_in6都是第一个成员是sockaddr结构的结构.

根据C标准,结构的地址和它的第一个成员是相同的,所以你可以将指针强制转换sockaddr_in(6)为指针sockaddr.

以功能sockaddr_in(6)为参数可修改sockaddr的部分,并采取功能sockaddr作为参数只关心那部分.

这有点像继承.

  • 我认为任何实现都不会将struct sockaddr作为其他struct sockaddr派生类的成员嵌入,例如struct sockaddr_in.它们的共同点是1. member`sa_family`,当给出struct sockaddr时,你用它来确定它是哪个实际的socket地址结构. (3认同)
  • *sockaddr_in 和 sockaddr_in6 都是结构,其中第一个成员是 sockaddr 结构。*。查看头文件时,我没有看到 `sockaddr_in` 具有 `sockaddr` 成员类型的成员。 (2认同)

Zij*_*gWu 21

我不想回答我的问题.但是为了提供更多可能对其他人有用的信息,我决定回答我的问题.

挖掘出源代码之后linux.以下是我的发现,可能有多种协议都可以实现getsockname.并且每个都有自己的地址数据结构,例如,对于IPv4,它是sockaddr_inIPV6 sockaddr_in6,sockaddr_un对于AF_UNIXsocket.sockaddr用作这些API签名中的公共数据支柱.

这些API会将memadpy中的socketaddr_in或sockaddr_in6或sockaddr_un复制到另一个参数length的sockaddr上.

并且所有数据结构都以相同的类型字段sa_family开头.

底座上的原因,该代码段是有效的,因为两者sockaddr_insockaddr_in6sa_family然后我们就可以检查后转换为正确的数据结构使用sa_family.

BTY,我不知道为什么sizeof(sockaddr_in6) > sizeof(sockaddr)导致基于sockaddr大小的内存分配对于ipv6来说还不够(这很容易出错),但我想这是因为历史原因.

  • 请注意,您不应该为struct sockaddr分配存储空间您总是分配一个具体的结构,例如struct sockaddr_in,struct sockaddr_in6.或者你分配一个结构sockaddr_storage,保证足够大的任何struct sockaddr(除了sockaddr_in和sockaddr_in6之外还有很多) (7认同)