首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不支持C/C++ getnameinfo ai_family

不支持C/C++ getnameinfo ai_family
EN

Stack Overflow用户
提问于 2016-06-30 20:21:56
回答 1查看 4.7K关注 0票数 1

我使用一个库来完成一些网络事务,当客户端连接时,这个库提供了一个“sockaddr *”,它保存了客户端套接字。我只是想提取IP和端口,目前我是这样做的:

代码语言:javascript
运行
复制
#include <sys/socket.h>
#include <netdb.h>

const std::string Client::prepareIPandPort(struct sockaddr *hostaddr) {
    assert(hostaddr != nullptr);

    std::string ipport;
    char clienthost[NI_MAXHOST];
    char clientport[NI_MAXSERV];
    int result = getnameinfo(hostaddr, sizeof(*hostaddr),
                             clienthost, sizeof(clienthost),
                             clientport, sizeof(clientport),
                             NI_NUMERICHOST | NI_NUMERICSERV);

    if (result != 0) {
        std::cerr << "Error: " << gai_strerror(result) << std::endl;
        ipport = "unknown";
    } else {
        switch (hostaddr->sa_family) {
            case AF_INET:
                ipport = std::string {clienthost} + ":"
                         + std::string {clientport};
                break;
            case AF_INET6:
                ipport = "[" + std::string {clienthost} + "]:"
                         + std::string {clientport};
                break;
            default:
                ipport = "unknown";
        }
    }

    return ipport;
}

在我的Mac上使用IPv4时,它可以工作。如果我在Gentoo Linux服务器上使用这个完全支持IPv6的应用程序,我只能得到:

错误:不支持ai_family

连接客户端具有AAAA和IP6记录。

我添加了一些couts并打印了hostaddr->sa_ some,它返回10,即AF_INET6。

为什么这不起作用?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-30 21:23:59

您不能使用sizeof(*hostaddr),因为hostaddr是一个通用的sockaddr*指针。不同的地址家族使用不同的sockaddr_...类型,这些类型与sockaddr本身的大小并不完全相同。getnameinfo()需要根据其地址系列知道hostaddr实际指向的sockaddr_...结构的真正大小。

根据Linux documentation

EAI_FAMILY 地址族无法识别,或地址长度对于指定的家族无效。

sockaddr_in ( IPv4 )与sockaddr的大小相同,这就是getnameinfo()为IPv4“工作”的原因。但是sockaddr_in6 (IPv6)比sockaddr大,这就是getnameinfo()失败的原因。

最好的解决方案是让调用方通过正确的大小:

代码语言:javascript
运行
复制
const std::string Client::prepareIPandPort(struct sockaddr *hostaddr, int hostaddrlen) {
    ...
    int result = getnameinfo(hostaddr, hostaddrlen, ...);
    ...
}

代码语言:javascript
运行
复制
sockaddr_in ipv4host;
...
client.prepareIPandPort((sockaddr*)&ipv4host, sizeof(ipv4host));

代码语言:javascript
运行
复制
sockaddr_in6 ipv6host;
...
client.prepareIPandPort((sockaddr*)&ipv6host, sizeof(ipv6host));

否则,您必须计算它:

代码语言:javascript
运行
复制
const std::string Client::prepareIPandPort(struct sockaddr *hostaddr) {
    ...
    int hostaddrlen;
    switch (hostaddr->sa_family) {
        case AF_INET:
            hostaddrlen = sizeof(sockaddr_in);
            break;
        case AF_INET6:
            hostaddrlen = sizeof(sockaddr_in6);
            break;
        default:
            std::cerr << "Error: " << gai_strerror(EAI_FAMILY) << std::endl;
            return "unknown";
    }
    int result = getnameinfo(hostaddr, hostaddrlen, ...);
    ...
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38132577

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档