C++ sockaddr、sockaddr_in 和 sockaddr_in6 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18609397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:03:52  来源:igfitidea点击:

What's the difference between sockaddr, sockaddr_in, and sockaddr_in6?

c++capinetwork-programming

提问by ZijingWu

I know that sockaddr_in is for IPv4, and sockaddr_in6 for IPv6. The confusion to me is the difference between sockaddr and sockaddr_in[6].

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

Some functions accept sockaddrand some functions accept sockaddr_inor sockaddr_in6, so:

有些函数接受sockaddr,有些函数接受sockaddr_inor sockaddr_in6,所以:

  • what's the rule?
  • And why is there a need for two different structures?
  • 规则是什么?
  • 为什么需要两种不同的结构?

And because the sizeof(sockaddr_in6) > sizeof(sockaddr) == sizeof(sockaddr_in).

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

  • Does that mean we should always use sockaddr_in6 to allocate memory in stack and cast to sockaddr and sockaddr_in if we need to support ipv4 and ipv6?
  • 这是否意味着如果我们需要支持 ipv4 和 ipv6,我们应该总是使用 sockaddr_in6 在堆栈中分配内存并强制转换为 sockaddr 和 sockaddr_in ?

One example is: we have a socket, and we want to get the string ip address of it (it can be ipv4 or ipv6).

一个例子是:我们有一个socket,我们想获取它的字符串ip地址(可以是ipv4或ipv6)。

We first call getsocknameto get an addrand then call inet_ntopbased on the addr.sa_family.

我们首先调用getsocknameget anaddr然后inet_ntop根据调用addr.sa_family

Is there anything wrong with this code snippet?

这个代码片段有什么问题吗?

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

采纳答案by ZijingWu

I don't want to answer my question. But to give more information here which might be useful to other people, I decide to answer my question.

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

After dig into the source code of linux. Following is my finding, there are possible multiple protocol which all implement the getsockname. And each have themself underling address data structure, for example, for IPv4 it is sockaddr_in, and IPV6 sockaddr_in6, and sockaddr_unfor AF_UNIXsocket. sockaddrare used as the common data strut in the signature of those APIs.

在深入研究linux. 以下是我的发现,可能有多种协议都实现了getsockname. 并且每个都有自己的底层地址数据结构,例如,对于IPv4,它是sockaddr_in,和IPV6 sockaddr_in6sockaddr_un对于AF_UNIX套接字。sockaddr在这些 API 的签名中用作公共数据支柱。

Those API will copy the socketaddr_in or sockaddr_in6 or sockaddr_un to sockaddr base on another parameter lengthby memcpy.

这些 API 将length根据 memcpy 的另一个参数将 socketaddr_in 或 sockaddr_in6 或 sockaddr_un 复制到 sockaddr 。

And all of the data structure begin with same type field sa_family.

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

Base on those reason, the code snippet is valid, because both sockaddr_inand sockaddr_in6have sa_familyand then we can cast it to the correct data structure for usage after check sa_family.

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

BTY, I'm not sure why the sizeof(sockaddr_in6) > sizeof(sockaddr), which cause allocate memory base on size of sockaddr is not enough for ipv6( that is error-prone), but I guess it is because of history reason.

BTY,我不确定为什么sizeof(sockaddr_in6) > sizeof(sockaddr)根据 sockaddr 的大小分配内存的 , 对 ipv6 来说是不够的(容易出错),但我想这是因为历史原因。

回答by linkdd

sockaddr_inand sockaddr_in6are both structures where first member is a sockaddrstructure.

sockaddr_insockaddr_in6都是结构,其中第一个成员是sockaddr结构。

According to the C standard, the address of a structure and its first member are the same, so you can cast the pointer to sockaddr_in(6)in a pointer to sockaddr.

根据 C 标准,结构的地址与其第一个成员的地址相同,因此您可以将指针转换sockaddr_in(6)为指向 的指针sockaddr

Functions taking sockaddr_in(6)as parameter may modify the sockaddrpart, and functions taking sockaddras parameter just care about that part.

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

It's a bit like inheritance.

有点像继承。