【问题标题】:casting sockaddr_storage as sockaddr_in for inet_ntop将 sockaddr_storage 转换为 inet_ntop 的 sockaddr_in
【发布时间】: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 时,我要么得到“无法转换为指针”,要么当我删除取消引用时,我得到“请求转换为非缩放器类型”。

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

【问题讨论】:

    标签: c sockets


    【解决方案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 中删除取消引用时,我得到“转换为非缩放器类型”错误
    猜你喜欢
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 2011-07-23
    • 2021-05-18
    • 2016-10-07
    相关资源
    最近更新 更多