sockaddr、sockaddr_in 和 sockaddr_in6 有什么区别? [英] What's the difference between sockaddr, sockaddr_in, and sockaddr_in6?

查看:56
本文介绍了sockaddr、sockaddr_in 和 sockaddr_in6 有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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,有些函数接受sockaddr_insockaddr_in6,所以:

Some functions accept sockaddr and some functions accept sockaddr_in or sockaddr_in6, so:

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

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

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

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

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

我们首先调用getsockname 获取addr,然后根据addr.sa_family 调用inet_ntop.

We first call getsockname to get an addr and then call inet_ntop based on the 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));
}

推荐答案

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

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.

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

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_un for AF_UNIX socket. sockaddr are used as the common data strut in the signature of those APIs.

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

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

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

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

基于这些原因,代码片段是有效的,因为 sockaddr_insockaddr_in6 都有 sa_family 然后我们可以将它转换为检查sa_family后使用正确的数据结构.

Base on those reason, the code snippet is valid, because both sockaddr_in and sockaddr_in6 have sa_family and then we can cast it to the correct data structure for usage after check sa_family.

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

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.

这篇关于sockaddr、sockaddr_in 和 sockaddr_in6 有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆