将 sockaddr_storage 转换为 inet_ntop 的 sockaddr_in

Posted

技术标签:

【中文标题】将 sockaddr_storage 转换为 inet_ntop 的 sockaddr_in【英文标题】:casting sockaddr_storage as sockaddr_in for inet_ntop 【发布时间】:2013-11-21 19:42:52 【问题描述】:

我正在尝试将 sockaddr_storage 转换为 sockadd_in,以便我可以打印出数据报包的源 IP 地址, 我似乎无法让演员表正确,

struct sockaddr_storage  peer_addr;


getnameinfo((struct sockaddr *) &peer_add
                peer_addrlen,
                hostbuff, sizeof(hostbuff),
                NULL, 0, NI_NAMEREQD);


inet_ntop(AF_INET, (((struct sockaddr_in *)peer_addr).sin_addr), ipbuff, INET_ADDRSTRLEN);

当我尝试将结构转换为 sockaddr_in 时,我要么得到“无法转换为指针”,要么当我删除取消引用时,我得到“请求转换为非缩放器类型”。

我尝试了很多组合,只是不明白我哪里出错了。

【问题讨论】:

【参考方案1】:
inet_ntop(peer_addr->ss_family, &(((struct sockaddr_in *)peer_addr)->sin_addr), ipbuff, INET_ADDRSTRLEN);

应该可以。但考虑改用getnameinfo(),这是更现代的 界面:

char host[NI_MAXHOST];
getnameinfo((struct sockaddr *)peer_addr, peer_addr->ss_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST);

适用于 IPv4 和 IPv6 地址。


更新根据问题中改变的类型:这是一个完整的例子 应该在没有警告的情况下编译:

int socket = ...;

struct sockaddr_storage peer_addr;
socklen_t peer_addrlen;
char host[NI_MAXHOST];

ssize_t amount;
char buffer[1000];
amount = recvfrom(socket, buffer, sizeof(buffer), 0, (struct sockaddr *)&peer_addr, &peer_addrlen);
getnameinfo((struct sockaddr *)&peer_addr, peer_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);

或者,使用inet_ntop()

char ipbuff[INET_ADDRSTRLEN];
inet_ntop(peer_addr.ss_family, &(((struct sockaddr_in *)&peer_addr)->sin_addr), ipbuff, INET_ADDRSTRLEN);

【讨论】:

我认为 getnameinfo() 返回了地址的主机名? @Babbleshack:有关 NI_NUMERICHOST 标志,请参见“man getnameinfo”:以数字形式返回地址,就像调用 inet_ntop(3),而不是主机名。 可移植的方式不是使用peer_addr->ss_family(至少在我的系统上还不知道),而是使用分配结构的实际大小。 @Babbleshack:请问您为什么“不接受”这个答案?它不再起作用了吗? - 当然 glglgl 是正确的,使用实际的 sockaddr 长度(例如由 recvfrom() 返回)是更便携的方式,但这不应该让我的回答完全错误。 - 如果你改变问题,它会令人困惑。最初,peer_addr 是一个 pointer 指向 struct sockaddr_storage,因此我的回答是假设的。 @MartinR 谢谢你的回答反映了我的工作代码。我已重新接受您的回答。【参考方案2】:
struct sockaddr_storage  *  peer_addr;


getnameinfo((struct sockaddr *) &peer_add
                peer_addrlen,
                hostbuff, sizeof(hostbuff),
                NULL, 0, NI_NAMEREQD);

你在这里混淆了东西。

getnameinfo() 确实将struct sockaddr* 作为它的第一个参数,但是你在这里尝试做的事情是行不通的:peer_addr 是一个struct sockaddr_storage *,你取它的地址 - 这是一个struct sockaddr_storage **,并尝试投射这个。那是行不通的。

我不知道你的peer_addr 来自哪里,但是

要么应该是struct sockaddr_storage(我认为不需要在某处有指向struct sockaddr_storage 的指针) 或者它真的是一个指针,你应该将(struct sockaddr *) peer_addr - 没有& - 传递给getnameinfo()

另外一点:getnameinfo() 的第二个参数应该是您输入的地址结构的“真实”大小。

【讨论】:

当我尝试这样做时,我得到一个编译错误,当我使用我的原始代码时,我的程序按预期工作。这是否意味着我有“未定义的行为” @Babbleshack 我不知道那是什么意思,因为我不知道你得到哪个编译错误。但你很可能会得到 UB,因为演员表可能会隐藏和隐藏问题。 当我从 sockaddr 中删除取消引用时,我得到“转换为非缩放器类型”错误

以上是关于将 sockaddr_storage 转换为 inet_ntop 的 sockaddr_in的主要内容,如果未能解决你的问题,请参考以下文章

UB与不同类型的结构铸件? [复制]

将 IPv4/IPv6 地址和端口设置为 sockaddr_storage 结构

如何理解存储在 sockaddr_storage 中的 IP 的 IP 版本

从 sockaddr_storage 中提取 IP 地址和端口信息

从sockaddr_storage中提取IP地址和端口信息

套接字编程,将 sockaddr_in 转换为 sockaddr。为啥?