getaddrinfo 函数 (ws2tcpip.h)

getaddrinfo 函数提供从 ANSI 主机名到地址的独立于协议的转换。

语法

INT WSAAPI getaddrinfo(
  [in, optional] PCSTR           pNodeName,
  [in, optional] PCSTR           pServiceName,
  [in, optional] const ADDRINFOA *pHints,
  [out]          PADDRINFOA      *ppResult
);

参数

[in, optional] pNodeName

指向以 NULL 结尾的 ANSI 字符串的指针,该字符串包含主机 (节点) 名称或主机地址数字字符串。 对于 Internet 协议,数字主机地址字符串是点十进制 IPv4 地址或 IPv6 十六进制地址。

[in, optional] pServiceName

指向以 NULL 结尾的 ANSI 字符串的指针,该字符串包含表示为字符串的服务名称或端口号。

服务名称是端口号的字符串别名。 例如,“http”是由 Internet 工程任务组定义的端口 80 的别名, (IETF) 作为 Web 服务器用于 HTTP 协议的默认端口。 以下文件中列出了未指定端口号时 pServiceName 参数的可能值:

%WINDIR%\system32\drivers\etc\services

[in, optional] pHints

指向 addrinfo 结构的指针,该结构提供有关调用方支持的套接字类型的提示。

pHints 参数指向的 addrinfo 结构的ai_addrlenai_canonnameai_addrai_next成员必须为零或 NULL。 否则, GetAddrInfoEx 函数将失败并 WSANO_RECOVERY

有关更多详细信息,请参阅“备注”。

[out] ppResult

指向包含有关主机的响应信息的一个或多个 addrinfo 结构的链接列表的指针。

返回值

成功返回零。 失败将返回非零 Windows 套接字错误代码,如 Windows 套接字错误代码中所示。

getaddrinfo 函数返回的大多数非零错误代码映射到 Internet 工程任务组概述的错误集, (IETF) 建议。 下表列出了这些错误代码及其 WSA 等效项。 建议使用 WSA 错误代码,因为它们为 Winsock 程序员提供熟悉且全面的错误信息。

错误值 WSA 等效项 说明
EAI_AGAIN WSATRY_AGAIN 名称解析暂时失败。
EAI_BADFLAGS WSAEINVAL pHints 参数的 ai_flags 成员提供的值无效。
EAI_FAIL WSANO_RECOVERY 名称解析中发生不可恢复的失败。
EAI_FAMILY WSAEAFNOSUPPORT 不支持 pHints 参数的 ai_family 成员。
EAI_MEMORY WSA_NOT_ENOUGH_MEMORY 发生内存分配失败。
EAI_NONAME WSAHOST_NOT_FOUND 未为提供的参数解析名称,或者未提供 pNodeNamepServiceName 参数。
EAI_SERVICE WSATYPE_NOT_FOUND pHints 参数的指定ai_socktype成员不支持 pServiceName 参数。
EAI_SOCKTYPE WSAESOCKTNOSUPPORT 不支持 pHints 参数的 ai_socktype 成员。
 

使用 gai_strerror 函数根据 getaddrinfo 函数返回的 EAI 代码打印错误消息。 提供 gai_strerror 函数是为了符合 IETF 建议,但它不是线程安全的。 因此,建议使用传统的 Windows 套接字函数,如 WSAGetLastError

错误代码 含义
WSA_NOT_ENOUGH_MEMORY
内存不足,无法执行该操作。
WSAEAFNOSUPPORT
使用了与请求的协议不兼容的地址。 如果不支持 pHints 参数指向的 addrinfo 结构的 ai_family 成员,则返回此错误。
WSAEINVAL
提供的参数无效。 如果为 pHints 参数指向的 addrinfo 结构的 ai_flags 成员提供了无效值,则返回此错误。
WSAESOCKTNOSUPPORT
在此地址族中不存在对指定的套接字类型的支持。 如果不支持 pHints 参数指向的 addrinfo 结构的 ai_socktype 成员,则返回此错误。
WSAHOST_NOT_FOUND
无法识别这种主机。 如果未为提供的参数解析名称,或者未提供 pNodeNamepServiceName 参数,则返回此错误。
WSANO_DATA
请求的名称有效,但找不到请求的类型的数据。
WSANO_RECOVERY
数据库查找期间发生不可恢复的错误。 如果名称解析中发生不可恢复的错误,则返回此错误。
WSANOTINITIALISED
在使用此函数之前,必须成功调用 WSAStartup
WSATRY_AGAIN
这通常是主机名解析期间的临时错误,意味着本地服务器未接收到来自授权服务器的响应。 发生名称解析的临时失败时,将返回此错误。
WSATYPE_NOT_FOUND
未找到指定的类。 pHints 参数指向的 addrinfo 结构的指定ai_socktype成员不支持 pServiceName 参数。

注解

getaddrinfo 函数是函数的 ANSI 版本,它提供从主机名到地址的独立于协议的转换。 此函数的 Unicode 版本为 GetAddrInfoW。 建议开发人员使用 GetAddrInfoW Unicode 函数,而不是 getaddrinfo ANSI 函数。

getaddrinfo 函数返回NS_DNS命名空间的结果。 如果多个命名空间提供程序返回信息, 则 getaddrinfo 函数会聚合所有响应。 若要与 IPv6 和 IPv4 协议一起使用,可以通过域名系统 (DNS) 、本地 主机 文件或 NS_DNS 命名空间的其他命名机制进行名称解析。

另一个可用于 getaddrinfo 函数的名称是 GetAddrInfoAWs2tcpip.h 头文件中的宏将 GetAddrInfoA 定义为 getaddrinfo

Ws2tcpip.h 头文件中的宏定义 GetAddrInfo 的混合大小写函数名称和 ADDRINFOT 结构。 应使用 TCHAR 类型的指针的 pNodeNamepServiceName 参数以及 ADDRINFOT 类型指针的 pHintsppResult 参数调用此 GetAddrInfo 函数。 如果未定义 UNICODE 或 _UNICODE, 则会将 GetAddrInfo 定义为 getaddrinfo、函数的 ANSI 版本,并将 ADDRINFOT 定义为 addrinfo 结构。 定义 UNICODE_UNICODE 时, 将 GetAddrInfo 定义为 GetAddrInfoW,函数的 Unicode 版本, ADDRINFOT 定义为 addrinfoW 结构。

平台软件开发工具包上的 Ws2tcpip.h 头文件中定义的 getaddrinfo 函数的参数名称和参数类型 (SDK) for Windows Server 2003 和 Windows XP 不同。

一个或两个 pNodeNamepServiceName 参数必须指向 以 NULL 结尾的 ANSI 字符串;通常同时提供这两种服务。

成功后,将在 ppResult 参数中返回 addrinfo 结构的链接列表。 可以按照每个返回的 addrinfo 结构的 ai_next 成员中提供的指针处理列表,直到遇到 NULL 指针。 在每个返回的 addrinfo 结构中, ai_familyai_socktypeai_protocol 成员对应于 套接字WSASocket 函数调用中的相应参数。 此外,每个返回的 addrinfo 结构中的 ai_addr 成员指向填充的套接字地址结构,其长度在其ai_addrlen成员中指定。

如果 pNodeName 参数指向计算机名称,则返回可用作源地址的计算机的所有永久地址。 在 Windows Vista 及更高版本中,这些地址将包括 GetUnicastIpAddressTableGetUnicastIpAddressEntry 函数返回的所有单播 IP 地址,其中 SkipAsSource 成员在 MIB_UNICASTIPADDRESS_ROW 结构中设置为 false。

如果 pNodeName 参数指向等于“localhost”的字符串,则返回本地计算机上的所有环回地址。

如果 pNodeName 参数包含空字符串,则返回本地计算机上所有已注册的地址。

在 Windows Server 2003 及更高版本中,如果 pNodeName 参数指向等于“.”的字符串。localmachine“,返回本地计算机上所有已注册的地址。

如果 pNodeName 参数引用群集虚拟服务器名称,则仅返回虚拟服务器地址。 在 Windows Vista 及更高版本上,这些地址将包括 GetUnicastIpAddressTableGetUnicastIpAddressEntry 函数返回的所有单播 IP 地址,其中的 SkipAsSource 成员在 MIB_UNICASTIPADDRESS_ROW 结构中设置为 true。 有关聚类分析的详细信息,请参阅 Windows 群集

Windows 7 Service Pack 1 (SP1) 和 Windows Server 2008 R2 service Pack 1 (SP1) 添加对 Netsh.exe 的支持,以在 IP 地址上设置 SkipAsSource 属性。 这还会更改行为,使MIB_UNICASTIPADDRESS_ROW结构中的 SkipAsSource 成员设置为 false,IP 地址将在 DNS 中注册。 如果 SkipAsSource 成员设置为 true,则 IP 地址未在 DNS 中注册。

修补程序适用于 Windows 7 和 Windows Server 2008 R2,这些修补程序支持 Netsh.exe 在 IP 地址上设置 SkipAsSource 属性。 此修补程序还会更改行为,以便如果MIB_UNICASTIPADDRESS_ROW结构中的 SkipAsSource 成员设置为 false,则会在 DNS 中注册 IP 地址。 如果 SkipAsSource 成员设置为 true,则 IP 地址未在 DNS 中注册。 有关详细信息,请参阅 知识库 (KB) 2386184

具有 Service Pack 2 (SP2) 的 Windows Vista 和 Windows Server 2008 Service Pack 2 (SP2) 也提供了类似的修补程序,为 Netsh.exe 添加对 IP 地址上设置 SkipAsSource 属性的支持。 此修补程序还会更改行为,以便如果MIB_UNICASTIPADDRESS_ROW结构中的 SkipAsSource 成员设置为 false,则会在 DNS 中注册 IP 地址。 如果 SkipAsSource 成员设置为 true,则 IP 地址未在 DNS 中注册。

getaddrinfo 函数的调用方可以提供有关通过 pHints 参数指向的 addrinfo 结构支持的套接字类型的提示。 使用 pHints 参数时,以下规则适用于其关联的 addrinfo 结构:

  • ai_family 的 AF_UNSPEC值表示调用 方将仅接受 AF_INETAF_INET6 地址系列。 请注意, AF_UNSPECPF_UNSPEC 是相同的。
  • ai_socktype的值为零表示调用方将接受任何套接字类型。
  • ai_protocol 的值为零表示调用方将接受任何协议。
  • ai_addrlen成员必须设置为零。
  • ai_canonname 成员必须设置为 NULL
  • ai_addr成员必须设置为 NULL
  • ai_next 成员必须设置为 NULL

ai_family 的 AF_UNSPEC值表示调用 方将接受任何协议系列。 此值可用于返回 pNodeName 参数指向的主机名的 IPv4 和 IPv6 地址。 在 Windows Server 2003 和 Windows XP 上,仅当本地计算机上安装 IPv6 时,才会返回 IPv6 地址。

pHints 参数中提供的 addrinfo 结构中的其他值指示特定要求。 例如,如果调用方仅处理 IPv4 而不处理 IPv6,则应将 ai_family 成员设置为 AF_INET。 对于另一个示例,如果调用方只处理 TCP 而不处理 UDP,则应将 ai_socktype 成员设置为 SOCK_STREAM

如果 pHints 参数为 NULL 指针,则 getaddrinfo 函数将其视为 pHints 中的 addrinfo 结构已初始化,其 ai_family 成员设置为 AF_UNSPEC 所有其他成员设置为零。

在 Windows Vista 及更高版本上,当从服务调用 getaddrinfo 时,如果操作是用户进程调用该服务的结果,则服务应模拟该用户。 这是为了允许正确强制实施安全性。

getaddrinfo 函数可用于将 IP 地址的文本字符串表示形式转换为 addrinfo 结构,该结构包含 IP 地址和其他信息的 sockaddr 结构。 若要以这种方式使用,pNodeName 参数指向的字符串必须包含 IP 地址的文本表示形式,并且 pHints 参数指向的 addrinfo 结构必须在 ai_flags 成员中设置AI_NUMERICHOST标志。 pNodeName 参数指向的字符串可能包含 IPv4 或 IPv6 地址的文本表示形式。 文本 IP 地址将转换为 ppResult 参数指向的 addrinfo 结构。 返回的 addrinfo 结构包含 IP 地址的 sockaddr 结构以及有关 IP 地址的附加信息。 若要使用 Windows Server 2003 和 Windows XP 上的 IPv6 地址字符串,必须在本地计算机上安装 IPv6 协议。 否则,将返回 WSAHOST_NOT_FOUND 错误。

从动态分配中释放地址信息

ppResult 参数指向的 getaddrinfo 函数返回的所有信息都是动态分配的,包括所有 addrinfo 结构、套接字地址结构和 addrinfo 结构指向的规范主机名字符串。 成功调用此函数分配的内存必须通过后续调用 freeaddrinfo 释放。

示例代码

下面的代码示例演示如何使用 getaddrinfo 函数。
#undef UNICODE

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

// link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")

int __cdecl main(int argc, char **argv)
{

    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult;
    INT iRetval;

    DWORD dwRetval;

    int i = 1;
    
    struct addrinfo *result = NULL;
    struct addrinfo *ptr = NULL;
    struct addrinfo hints;

    struct sockaddr_in  *sockaddr_ipv4;
//    struct sockaddr_in6 *sockaddr_ipv6;
    LPSOCKADDR sockaddr_ip;

    char ipstringbuffer[46];
    DWORD ipbufferlength = 46;

    // Validate the parameters
    if (argc != 3) {
        printf("usage: %s <hostname> <servicename>\n", argv[0]);
        printf("getaddrinfo provides protocol-independent translation\n");
        printf("   from an ANSI host name to an IP address\n");
        printf("%s example usage\n", argv[0]);
        printf("   %s www.contoso.com 0\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    //--------------------------------
    // Setup the hints address info structure
    // which is passed to the getaddrinfo() function
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    printf("Calling getaddrinfo with following parameters:\n");
    printf("\tnodename = %s\n", argv[1]);
    printf("\tservname (or port) = %s\n\n", argv[2]);
    
//--------------------------------
// Call getaddrinfo(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response
// information
    dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
    if ( dwRetval != 0 ) {
        printf("getaddrinfo failed with error: %d\n", dwRetval);
        WSACleanup();
        return 1;
    }

    printf("getaddrinfo returned success\n");
    
    // Retrieve each address and print out the hex bytes
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        printf("getaddrinfo response %d\n", i++);
        printf("\tFlags: 0x%x\n", ptr->ai_flags);
        printf("\tFamily: ");
        switch (ptr->ai_family) {
            case AF_UNSPEC:
                printf("Unspecified\n");
                break;
            case AF_INET:
                printf("AF_INET (IPv4)\n");
                sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
                printf("\tIPv4 address %s\n",
                    inet_ntoa(sockaddr_ipv4->sin_addr) );
                break;
            case AF_INET6:
                printf("AF_INET6 (IPv6)\n");
                // the InetNtop function is available on Windows Vista and later
                // sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
                // printf("\tIPv6 address %s\n",
                //    InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstringbuffer, 46) );
                
                // We use WSAAddressToString since it is supported on Windows XP and later
                sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
                // The buffer length is changed by each call to WSAAddresstoString
                // So we need to set it for each iteration through the loop for safety
                ipbufferlength = 46;
                iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, 
                    ipstringbuffer, &ipbufferlength );
                if (iRetval)
                    printf("WSAAddressToString failed with %u\n", WSAGetLastError() );
                else    
                    printf("\tIPv6 address %s\n", ipstringbuffer);
                break;
            case AF_NETBIOS:
                printf("AF_NETBIOS (NetBIOS)\n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_family);
                break;
        }
        printf("\tSocket type: ");
        switch (ptr->ai_socktype) {
            case 0:
                printf("Unspecified\n");
                break;
            case SOCK_STREAM:
                printf("SOCK_STREAM (stream)\n");
                break;
            case SOCK_DGRAM:
                printf("SOCK_DGRAM (datagram) \n");
                break;
            case SOCK_RAW:
                printf("SOCK_RAW (raw) \n");
                break;
            case SOCK_RDM:
                printf("SOCK_RDM (reliable message datagram)\n");
                break;
            case SOCK_SEQPACKET:
                printf("SOCK_SEQPACKET (pseudo-stream packet)\n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_socktype);
                break;
        }
        printf("\tProtocol: ");
        switch (ptr->ai_protocol) {
            case 0:
                printf("Unspecified\n");
                break;
            case IPPROTO_TCP:
                printf("IPPROTO_TCP (TCP)\n");
                break;
            case IPPROTO_UDP:
                printf("IPPROTO_UDP (UDP) \n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_protocol);
                break;
        }
        printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
        printf("\tCanonical name: %s\n", ptr->ai_canonname);
    }

    freeaddrinfo(result);
    WSACleanup();

    return 0;
}

注意 确保开发环境面向最新版本的 Ws2tcpip.h ,其中分别包括 addrinfogetaddrinfo 的结构和函数定义。
 

国际化域名

Internet 主机名通常由一组非常受限的字符组成:
  • 英文字母表中的大小写 ASCII 字母。
  • 从 0 到 9 的数字。
  • ASCII 连字符。

随着 Internet 的发展,越来越需要为不由 ASCII 字符集表示的其他语言标识 Internet 主机名。 满足此需求并允许 Unicode) 表示为特殊 ASCII 字符串的非 ASCII 字符 (标识符称为国际化域名 (IDN) 。 (IDNA) 应用程序中称为国际化域名的机制用于以标准方式处理 IDN。 INTERNET 工程任务组 (IETF) 发布的 RFC 3490RTF 5890RFC 6365 中记录了 IDN 和 IDNA 的规范。

在Windows 8和Windows Server 2012,getaddrinfo 函数支持国际化域名 (IDN) 分析应用于 pNodeName 参数中传递的名称。 Winsock 执行 Punycode/IDN 编码和转换。 可以使用下面讨论的 AI_DISABLE_IDN_ENCODING 标志禁用此行为。

在 Windows 7 和 Windows Server 2008 R2 或更早版本上, getaddrinfo 函数当前不提供应用于 pNodeName 参数中传递的名称的支持 IDN 分析。 Winsock 不执行任何 Punycode/IDN 转换。 根据 RFC 3490,GetAddrInfo 函数的宽字符版本不使用 Punycode 转换 IDN。 查询 DNS 时 GetAddrInfo 函数的宽字符版本会将 Unicode 名称编码为 UTF-8 格式,即企业环境中 Microsoft DNS 服务器使用的格式。

Windows Vista 和更高版本上的多个函数支持在 IDN 中的 Unicode 标签与其 ASCII 等效项之间进行转换。 每个 Unicode 标签的结果表示形式仅包含 ASCII 字符,并且如果 Unicode 标签包含任何非 ASCII 字符,则以 xn - 前缀开头。 这样做的原因是支持 Internet 上的现有 DNS 服务器,因为某些 DNS 工具和服务器仅支持 ASCII 字符 (请参阅 RFC 3490) 。

IdnToAscii 函数使用 Punycode,使用 RFC 3490 中定义的标准算法将 IDN 转换为原始 Unicode 字符串的 ASCII 表示形式。 IdnToUnicode 函数将 IDN 的 ASCII 形式转换为正常的 Unicode UTF-16 编码语法。 有关相关标准草案的详细信息和链接,请参阅处理国际化 域名 (IDN)

IdnToAscii 函数可用于将 IDN 名称转换为 ASCII 形式,然后可在 pNodeName 参数中传递给 getaddrinfo 函数。 若要在) 定义 UNICODE 或 (_UNICODE 时使用此函数的宽字符版本时将此 IDN 名称传递给 GetAddrInfo 函数,可以使用 MultiByteToWideChar 函数将 CHAR 字符串转换为 WCHAR 字符串。

在 pHints 参数中使用ai_flags

pHints 参数中提供的可选 addrinfo 结构的 ai_flags 成员中的标志修改函数的行为。

这些标志位在适用于 Windows 7 的 Microsoft Windows 软件开发工具包 (Windows SDK) (SDK) 上的 Ws2def.h 头文件中定义。 这些标志位在 Windows Server 2008 和 Windows Vista Windows SDK上的 Ws2tcpip.h 头文件中定义。 这些标志位在适用于 Windows Server 2003 和 Windows XP 的平台 SDK 上的 Ws2tcpip.h 头文件中定义。

标志位可以是以下各项的组合:

标记位 说明
AI_PASSIVE 设置 AI_PASSIVE 标志表示调用方打算在 调用绑定 函数时使用返回的套接字地址结构。 如果设置了 AI_PASSIVE 标志并且 pNodeNameNULL 指针,则套接字地址结构的 IP 地址部分将设置为 IPv4 地址的INADDR_ANY,对于 IPv6 地址 IN6ADDR_ANY_INIT

如果未设置 AI_PASSIVE 标志,则返回的套接字地址结构已准备好调用面向连接的协议的 connect 函数,或者已准备好调用无连接协议的 connectsendtosend 函数。 在这种情况下,如果 pNodeName 参数为 NULL 指针,则套接字地址结构的 IP 地址部分设置为环回地址。

AI_CANONNAME 如果未使用 AI_CANONNAMEAI_NUMERICHOST ,则 getaddrinfo 函数将尝试解析。 如果传递了文本字符串 ,getaddrinfo 将尝试转换字符串,如果传递了主机名, 则 getaddrinfo 函数将尝试将名称解析为一个或多个地址。

设置 AI_CANONNAME 位后, pNodeName 参数不能为 NULL。 否则, getaddrinfo 函数将失败并 WSANO_RECOVERY

设置AI_CANONNAME位并且 getaddrinfo 函数返回成功时,ppResult 参数中的ai_canonname成员指向包含指定节点的规范名称的以 NULL 结尾的字符串。

注意设置AI_CANONNAME标志时,getaddrinfo 函数可以返回成功,但关联的 addrinfo 结构中的ai_canonname成员为 NULL。 因此,建议使用 AI_CANONNAME 标志包括测试关联的 addrinfo 结构中的 ai_canonname 成员是否为 NULL
 
AI_NUMERICHOST 设置 AI_NUMERICHOST 位后, pNodeName 参数必须包含非 NULL 数字主机地址字符串,否则将返回 EAI_NONAME 错误。 此标志阻止调用名称解析服务。
AI_NUMERICSERV 设置 AI_NUMERICSERV 位时, pServiceName 参数必须包含非 NULL 数字端口号,否则返回 EAI_NONAME 错误。 此标志阻止调用名称解析服务。

AI_NUMERICSERV标志在 Windows Vista 及更高版本的 Windows SDK上定义。 Microsoft 提供商不支持 AI_NUMERICSERV 标志。

AI_ALL 如果设置了 AI_ALL 位,则会对具有 AI_V4MAPPED的 IPv6 地址和 IPv4 地址发出请求。

AI_ALL标志在 Windows Vista 及更高版本的Windows SDK上定义。 Windows Vista 及更高版本支持 AI_ALL 标志。

AI_ADDRCONFIG 如果设置了 AI_ADDRCONFIG 位,则仅当配置了全局地址时 ,getaddrinfo 才会解析。 如果指定 了 AI_ADDRCONFIG 标志,则仅当在本地系统上配置了 IPv4 地址时,才返回 IPv4 地址,而仅当在本地系统上配置 IPv6 地址时,才返回 IPv6 地址。 IPv4 或 IPv6 环回地址不被视为有效的全局地址。

AI_ADDRCONFIG标志在 Windows Vista 及更高版本的Windows SDK上定义。 Windows Vista 及更高版本支持 AI_ADDRCONFIG 标志。

AI_V4MAPPED 如果设置了 AI_V4MAPPED 位,并且 IPv6 地址请求失败,则会对 IPv4 地址发出名称服务请求,这些地址将转换为 IPv4 映射的 IPv6 地址格式。

AI_V4MAPPED标志在 Windows Vista 及更高版本的Windows SDK上定义。 Windows Vista 及更高版本支持 AI_V4MAPPED 标志。

AI_NON_AUTHORITATIVE 如果设置了 AI_NON_AUTHORITATIVE 位, 则NS_EMAIL 命名空间提供程序将返回权威和非权威结果。 如果未设置 AI_NON_AUTHORITATIVE 位, 则NS_EMAIL 命名空间提供程序仅返回权威结果。

AI_NON_AUTHORITATIVE标志在 Windows Vista 及更高版本的Windows SDK上定义。 AI_NON_AUTHORITATIVE 标志在 Windows Vista 及更高版本上受支持,并且仅适用于 NS_EMAIL 命名空间。

AI_SECURE 如果设置了 AI_SECURE 位, NS_EMAIL 命名空间提供程序将返回以增强的安全性获取的结果,以最大程度地减少可能的欺骗。

AI_SECURE标志在 Windows Vista 及更高版本的Windows SDK上定义。 AI_SECURE标志在 Windows Vista 及更高版本上受支持,并且仅适用于NS_EMAIL命名空间。

AI_RETURN_PREFERRED_NAMES 如果设置了 AI_RETURN_PREFERRED_NAMES ,则不应在 pNodeName 参数中提供任何名称。 NS_EMAIL命名空间提供程序将返回发布的首选名称。

AI_RETURN_PREFERRED_NAMES标志在 Windows Vista 及更高版本的Windows SDK上定义。 AI_RETURN_PREFERRED_NAMES标志在 Windows Vista 及更高版本上受支持,并且仅适用于NS_EMAIL命名空间。

AI_FQDN 如果设置了 AI_FQDN ,并且指定了单标签) (平面名称, 则 getaddrinfo 将返回该名称最终解析为的完全限定域名。 完全限定的域名在关联的 addrinfo 结构的 ai_canonname 成员中返回。 这不同于 AI_CANONNAME 位标志,后者返回在 DNS 中注册的规范名称,该规范名称可能与平面名称解析到的完全限定域名不同。 只能设置一个 AI_FQDN 位和 AI_CANONNAME 位。 如果两个标志都带有EAI_BADFLAGS则 getaddrinfo 函数将失败。

设置 AI_FQDN 位后, pNodeName 参数不能为 NULL。 否则, GetAddrInfoEx 函数将失败并 WSANO_RECOVERY

Windows 7: AI_FQDN标志在 Windows 7 及更高版本的Windows SDK上定义。 Windows 7 及更高版本支持 AI_FQDN 标志。

AI_FILESERVER 如果设置了 AI_FILESERVER ,则会提示命名空间提供程序正在文件共享方案中使用正在查询的主机名。 命名空间提供程序可能会忽略此提示。

Windows 7: AI_FILESERVER标志在 Windows 7 及更高版本的Windows SDK上定义。 Windows 7 及更高版本支持 AI_FILESERVER 标志。

 

使用 AI_NUMERICHOST 的示例代码

下面的代码示例演示如何使用 getaddrinfo 函数将 IP 地址的文本字符串表示形式转换为 addrinfo 结构,该结构包含 IP 地址和其他信息的 sockaddr 结构。
#undef UNICODE

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

// link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")

int __cdecl main(int argc, char **argv)
{

    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult;

    DWORD dwRetval;

    int i = 1;
    
    struct addrinfo *result = NULL;
    struct addrinfo *ptr = NULL;
    struct addrinfo hints;


    // Validate the parameters
    if (argc != 2) {
        printf("usage: %s <IP Address String>\n", argv[0]);
        printf("  getaddrinfo determines the IP binary network address\n");
        printf("       %s 207.46.197.32\n", argv[0]);  /* www.contoso.com */
        return 1;
    }
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    //--------------------------------
    // Setup the hints address info structure
    // which is passed to the getaddrinfo() function
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_flags = AI_NUMERICHOST;
    hints.ai_family = AF_UNSPEC;
//    hints.ai_socktype = SOCK_STREAM;
//    hints.ai_protocol = IPPROTO_TCP;


//--------------------------------
// Call getaddrinfo(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response
// information
    dwRetval = getaddrinfo(argv[1], NULL, &hints, &result);
    if ( dwRetval != 0 ) {
        printf("getaddrinfo failed with error: %d\n", dwRetval);
        WSACleanup();
        return 1;
    }

    printf("getaddrinfo returned success\n");
    
    // Retrieve each address and print out the hex bytes
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        printf("getaddrinfo response %d\n", i++);
        printf("\tFlags: 0x%x\n", ptr->ai_flags);
        printf("\tFamily: ");
        switch (ptr->ai_family) {
            case AF_UNSPEC:
                printf("Unspecified\n");
                break;
            case AF_INET:
                printf("AF_INET (IPv4)\n");
                break;
            case AF_INET6:
                printf("AF_INET6 (IPv6)\n");
                break;
            case AF_NETBIOS:
                printf("AF_NETBIOS (NetBIOS)\n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_family);
                break;
        }
        printf("\tSocket type: ");
        switch (ptr->ai_socktype) {
            case 0:
                printf("Unspecified\n");
                break;
            case SOCK_STREAM:
                printf("SOCK_STREAM (stream)\n");
                break;
            case SOCK_DGRAM:
                printf("SOCK_DGRAM (datagram) \n");
                break;
            case SOCK_RAW:
                printf("SOCK_RAW (raw) \n");
                break;
            case SOCK_RDM:
                printf("SOCK_RDM (reliable message datagram)\n");
                break;
            case SOCK_SEQPACKET:
                printf("SOCK_SEQPACKET (pseudo-stream packet)\n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_socktype);
                break;
        }
        printf("\tProtocol: ");
        switch (ptr->ai_protocol) {
            case 0:
                printf("Unspecified\n");
                break;
            case IPPROTO_TCP:
                printf("IPPROTO_TCP (TCP)\n");
                break;
            case IPPROTO_UDP:
                printf("IPPROTO_UDP (UDP) \n");
                break;
            default:
                printf("Other %ld\n", ptr->ai_protocol);
                break;
        }
        printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
        printf("\tCanonical name: %s\n", ptr->ai_canonname);
    }

    freeaddrinfo(result);
    WSACleanup();

    return 0;
}

支持 Windows 2000 和更早版本上的 getaddrinfo

getaddrinfo 函数已添加到 Windows XP 及更高版本的 Ws2_32.dll。 若要在早期版本的 Windows 上执行使用此函数的应用程序,需要包含 Ws2tcpip.hWspiapi.h 文件。 添加 Wspiapi.h 包含文件时,getaddrinfo 函数将定义为 WspiapiGetAddrInfo 文件中的 WspiapiGetAddrInfo联函数。 在运行时, WspiapiGetAddrInfo 函数的实现方式如下:如果 Ws2_32.dll 或 Wship6.dll (包含适用于 Windows 2000) 的 IPv6 技术预览版中的 getaddrinfo 的文件不包含 getaddrinfo,则根据 Wspiapi.h 头文件中的代码内联实现 getaddrinfo 的版本。 此内联代码将用于本机不支持 getaddrinfo 函数的旧 Windows 平台。

安装适用于 Windows 2000 的 IPv6 技术预览版后,Windows 2000 支持 IPv6 协议。 否则,对早于 Windows XP 的 Windows 版本的 getaddrinfo 支持仅限于处理 IPv4 名称解析。

GetAddrInfoW 函数是 getaddrinfo 的 Unicode 版本。 GetAddrInfoW 函数已添加到 Windows XP service Pack 2 (SP2) 中的 Ws2_32.dll。 GetAddrInfoW 函数不能用于早于带 SP2 的 Windows XP 的 Windows 版本。

Windows Phone 8:Windows Phone 8 及更高版本上的 Windows Phone 应用商店应用支持此函数。

Windows 8.1Windows Server 2012 R2:Windows 8.1、Windows Server 2012 R2 及更高版本的 Windows 应用商店应用支持此函数。

要求

要求
最低受支持的客户端 Windows 8.1、Windows Vista [桌面应用 |UWP 应用]
最低受支持的服务器 Windows Server 2003 [桌面应用 | UWP 应用]
目标平台 Windows
标头 ws2tcpip.h
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

GetAddrInfoEx

GetAddrInfoW

IdnToAscii

IdnToUnicode

WSAGetLastError

WSASocket

Winsock 函数

Winsock 参考

addrinfo

addrinfoW

addrinfoex

addrinfoex2

bind

connect

freeaddrinfo

gai_strerror

send

sendto

socket