C 带有IPv6的getaddrinfo()没有意义

C 带有IPv6的getaddrinfo()没有意义,c,sockets,winapi,ipv6,getaddrinfo,C,Sockets,Winapi,Ipv6,Getaddrinfo,我不明白为什么getaddrinfo没有返回有效的IPv6地址 在我的系统上,下面的代码正在打印22:B8:00:00:00:00:00:00:00:00,但我希望在某个地方出现01,因为localhost应该解析为::1 同时,sau data只有14个字节,而IPv6地址是16个字节,所以最后两个字节似乎总是被截断,函数不能返回IPv6地址 有人能解释一下发生了什么事吗?我应该如何在IPv6中使用此功能 #include <stdio.h> #include <WinSoc

我不明白为什么
getaddrinfo
没有返回有效的IPv6地址

在我的系统上,下面的代码正在打印
22:B8:00:00:00:00:00:00:00:00
,但我希望在某个地方出现
01
,因为
localhost
应该解析为
::1

同时,
sau data
只有14个字节,而IPv6地址是16个字节,所以最后两个字节似乎总是被截断,函数不能返回IPv6地址

有人能解释一下发生了什么事吗?我应该如何在IPv6中使用此功能

#include <stdio.h>
#include <WinSock2.h>
#include <WS2TCPIP.h>
#pragma comment(lib, "WS2_32")

int main(int argc, char *argv[])
{
    WSADATA wsadata;
    WSAStartup(0x0002, &wsadata);
    addrinfo addr_hints = { 0, PF_INET6, SOCK_DGRAM, IPPROTO_UDP }, *addrs_out;
    getaddrinfo("localhost", "8888", &addr_hints, &addrs_out);
    fprintf(stderr,
        "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 0]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 1]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 2]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 3]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 4]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 5]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 6]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 7]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 8]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[ 9]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[10]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[11]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[12]),
        static_cast<unsigned char>(addrs_out->ai_addr->sa_data[13]));
    freeaddrinfo(addrs_out);
    return 0;
}
#包括
#包括
#包括
#pragma注释(lib,“WS2_32”)
int main(int argc,char*argv[])
{
WSADATA WSADATA;
WSAStartup(0x0002和wsadata);
addrinfo addr_hints={0,PF_INET6,SOCK_DGRAM,IPPROTO_UDP},*addr_out;
getaddrinfo(“localhost”、“8888”、&addr\u提示、&addr\u输出);
fprintf(标准,
%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n“,
静态广播(地址输出->人工智能地址->模拟音频数据[0]),
静态广播(地址输出->人工智能地址->模拟音频数据[1]),
静态数据转换(地址输出->人工智能地址->模拟退火数据[2]),
静态广播(地址输出->人工智能地址->模拟音频数据[3]),
静态广播(地址输出->人工智能地址->模拟音频数据[4]),
静态广播(地址输出->人工智能地址->模拟音频数据[5]),
静态广播(地址输出->人工智能地址->模拟音频数据[6]),
静态广播(地址输出->人工智能地址->模拟音频数据[7]),
静态广播(地址输出->人工智能地址->模拟音频数据[8]),
静态广播(地址输出->人工智能地址->模拟音频数据[9]),
静态广播(地址输出->人工智能地址->模拟音频数据[10]),
静态数据转换(地址输出->人工智能地址->模拟退火数据[11]),
静态数据转换(地址输出->人工智能地址->模拟退火数据[12]),
静态广播(地址输出->人工智能地址->模拟音频数据[13]);
freeaddrinfo(addrs_out);
返回0;
}

sockaddr
结构定义供参考:

struct sockaddr {
    ushort  sa_family;
    char    sa_data[14];
};


struct sockaddr_in6 {
    short   sin6_family;
    u_short sin6_port;
    u_long  sin6_flowinfo;
    struct  in6_addr sin6_addr;
    u_long  sin6_scope_id;
};
ai_family==AF_INET6
ai_addr
实际指向
结构sockaddr_in6
时。打印的前几个字节是
sin6\u端口
sin6\u流量信息
。IPv6地址在后面

编辑以添加:

您可以将
ai\u addr
直接与
bind()
getnameinfo()
等函数一起使用。您通常不需要深入了解结构定义的详细信息。例如,我将使用
getnameinfo()
NI\u numericost
来获取可打印的地址

没有严格解释为指向 sockaddr结构。该结构在本章中有不同的解释 不同地址族的上下文

因此,我们需要首先检查
sau族
ai_族
addrinfo
(在此基础上,它必须相等),并基于此需要将指针从(类似
void*
指针)重新解释为实际结构。为此,请使用union:

addrinfo *addrs_out, *addr;

if (getaddrinfo("localhost", "8888", 0, &addrs_out) == NOERROR)
{
    addr = addrs_out;

    CHAR buf[256], *sz, srv[128];
    ULONG n;
    PUCHAR Byte;

    do 
    {
        union {
            sockaddr* ai_addr;
            SOCKADDR_IN* pa;
            SOCKADDR_IN6* pa6;
        };

        ai_addr = addr->ai_addr;

        if (addr->ai_family != ai_addr->sa_family)
        {
            __debugbreak();
        }

        switch (addr->ai_family)
        {
        case AF_INET6:
            Byte = pa6->sin6_addr.u.Byte, n = RTL_NUMBER_OF(pa6->sin6_addr.u.Byte), sz = buf;
            do 
            {
                sz += sprintf(sz, "%02X:", *Byte++);
            } while (--n);

            sz[-1] = 0;
            DbgPrint("AF_INET6: %s\n", buf);
            break;

        case AF_INET:
            if (0 <= RtlIpv4AddressToStringExA(&pa->sin_addr.S_un.S_addr, pa->sin_port, buf, &(n = RTL_NUMBER_OF(buf))))
            {
                DbgPrint("AF_INET: %s\n", buf);
            }
            break;
        }

        // alt print
        if (getnameinfo(ai_addr, (socklen_t)addr->ai_addrlen, buf, RTL_NUMBER_OF(buf), srv, RTL_NUMBER_OF(srv), NI_NUMERICHOST ) == NOERROR)
        {
            DbgPrint("%s:%s\n", buf, srv);
        }

    } while (addr = addr->ai_next);

    freeaddrinfo(addrs_out);
}
addrinfo*addrs\u out,*addr;
if(getaddrinfo(“localhost”、“8888”、0和addrs\u out)=NOERROR)
{
addr=addrs\u out;
CHAR-buf[256],*sz,srv[128];
乌隆;
PUCHAR字节;
做
{
联合{
sockaddr*ai_addr;
SOCKADDR_IN*pa;
SOCKADDR_in 6*pa6;
};
ai_addr=addr->ai_addr;
如果(地址->ai_族!=ai_地址->sa_族)
{
__debugbreak();
}
开关(地址->人工智能系列)
{
案例6:
Byte=pa6->sin6\u addr.u.Byte,n=RTL\u编号(pa6->sin6\u addr.u.Byte),sz=buf;
做
{
sz+=sprintf(sz,“%02X:”,*Byte++);
}而(--n);
sz[-1]=0;
DbgPrint(“AF\u INET6:%s\n”,buf);
打破
案例分析:
如果(0 sin_addr.S_un.S_addr,pa->sin_port,buf,&(n=RTL_编号(buf)))
{
DbgPrint(“AF\U INET:%s\n”,buf);
}
打破
}
//alt打印
如果(getnameinfo(ai_addr,(socklen_t)addr->ai_addrlen,buf,RTL_NUMBER OF(buf),srv,RTL_NUMBER OF(srv),NI_numericost)=NOERROR)
{
DbgPrint(“%s:%s\n”,buf,srv);
}
}while(addr=addr->ai_next);
freeaddrinfo(addrs_out);
}

首先确保检查
getaddrinfo()
的返回值。如果失败,你的地址将是垃圾。@Jeff:我在我的实际代码中;这不是问题所在。噢,伙计,我以为
sockaddr
足够大,可以容纳
sockaddr\u在6
中,但这似乎就是
sockaddr\u存储的用途!这终于有道理了,谢谢!附带问题,但你知道有没有一个地方列出了每个标准地址家庭的长度吗?@Mehrdad,我不知道。其中有40种,它们自己的sockaddr定义散布在各种头文件中。