将 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的主要内容,如果未能解决你的问题,请参考以下文章
将 IPv4/IPv6 地址和端口设置为 sockaddr_storage 结构
如何理解存储在 sockaddr_storage 中的 IP 的 IP 版本