ADDRINFOEXW 结构 (ws2def.h)

GetAddrInfoEx 函数使用 addrinfoex 结构来保存主机地址信息。

语法

typedef struct addrinfoexW {
  int                ai_flags;
  int                ai_family;
  int                ai_socktype;
  int                ai_protocol;
  size_t             ai_addrlen;
  PWSTR              ai_canonname;
  struct sockaddr    *ai_addr;
  void               *ai_blob;
  size_t             ai_bloblen;
  LPGUID             ai_provider;
  struct addrinfoexW *ai_next;
} ADDRINFOEXW, *PADDRINFOEXW, *LPADDRINFOEXW;

成员

ai_flags

类型:int

指示 GetAddrInfoEx 函数中使用的选项的标志。

ai_flags 成员支持的值在 Winsock2.h 包含文件中定义,并且可以是以下选项的组合。

价值 意义
AI_PASSIVE
0x01
套接字地址将在调用 绑定 函数时使用。
AI_CANONNAME
0x02
规范名称在第一个 ai_canonname 成员中返回。

当同时设置 AI_CANONNAMEAI_FQDN 位时,addrinfoex2 结构不会返回 addrinfoex 结构。

AI_NUMERICHOST
0x04
传递给 GetAddrInfoEx 函数的 nodename 参数必须是数值字符串。
AI_ALL
0x0100
如果设置了此位,则会为具有 AI_V4MAPPED的 IPv6 地址和 IPv4 地址发出请求。

Windows Vista 及更高版本支持此选项。

AI_ADDRCONFIG
0x0400
仅当配置全局地址时,GetAddrInfoEx 才会解析。 IPv6 和 IPv4 环回地址不被视为有效的全局地址。

此选项仅在 Windows Vista 及更高版本上受支持。

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

Windows Vista 及更高版本支持此选项。

AI_NON_AUTHORITATIVE
0x04000
地址信息来自非权威结果。

GetAddrInfoExpHints 参数中设置此选项时,NS_EMAIL 命名空间提供程序将返回权威和非权威结果。 如果未设置此选项,则仅返回权威结果。

GetAddrInfoEx返回的 ppResults 参数中,此标志在非权威结果的 addrinfoex 结构的 ai_flags 成员中设置。

此选项仅在 Windows Vista 及更高版本上受 NS_EMAIL 命名空间支持。

AI_SECURE
0x08000
地址信息来自安全通道。 如果设置了 AI_SECURE 位,则 NS_EMAIL 命名空间提供程序将返回通过增强的安全性获取的结果,以最大程度地减少可能的欺骗。

GetAddrInfoExpHints 参数中设置此选项时,NS_EMAIL 命名空间提供程序仅返回通过增强的安全性获取的结果,以最大程度地减少可能的欺骗。

GetAddrInfoEx返回的 ppResults 参数中,此标志在 addrinfoex 结构 ai_flags 成员中设置,以增强安全性返回的结果,以最大程度地减少可能的欺骗。

此选项仅在 Windows Vista 及更高版本上受 NS_EMAIL 命名空间支持。

AI_RETURN_PREFERRED_NAMES
0x010000
地址信息适用于具有特定命名空间的发布的首选名称。

GetAddrInfoExpHints 参数中设置此选项时,pName 参数中不应提供任何名称,NS_EMAIL 命名空间提供程序将返回发布的首选名称。

GetAddrInfoEx返回的 ppResults 参数中,此标志在 addrinfoex 结构 ai_flags 成员中设置,以便为发布的首选名称返回的结果。

此选项仅在 Windows Vista 及更高版本上受 NS_EMAIL 命名空间支持。

AI_FQDN
0x00020000
完全限定的域名在第一个 ai_canonicalname 成员中返回。

GetAddrInfoExpHints 参数中设置此选项时,pName 参数中指定了平面名称(单一标签),则最终解析为该名称的完全限定域名将返回。

当同时设置 AI_CANONNAMEAI_FQDN 位时,addrinfoex2 结构不会返回 addrinfoex 结构。

Windows 7、Windows Server 2008 R2 及更高版本支持此选项。

AI_FILESERVER
0x00040000
命名空间提供程序提示正在文件共享方案中使用要查询的主机名。 命名空间提供程序可能会忽略此提示。

Windows 7、Windows Server 2008 R2 及更高版本支持此选项。

AI_DISABLE_IDN_ENCODING
0x00080000
getAddrInfoEx 函数调用的名称解析函数中使用 Punycode 禁用自动国际域名编码。

Windows 8、Windows Server 2012 及更高版本支持此选项。

ai_family

类型:int

地址系列。 地址系列的可能值在 Winsock2.h include 文件中定义。

在适用于 Windows Vista 及更高版本的 Windows SDK 上,头文件的组织已更改,地址系列的可能值在 Ws2def.h 头文件中定义。 请注意,Ws2def.h 头文件自动包含在 Winsock2.h中,不应直接使用。

当前支持的值是 AF_INETAF_INET6,它们是 IPv4 和 IPv6 的 Internet 地址系列格式。 如果安装了地址系列的 Windows 套接字服务提供商,则支持地址系列的其他选项(例如,用于 NetBIOS 的AF_NETBIOS)。 请注意,AF_地址系列和PF_协议系列常量的值相同(例如,AF_UNSPECPF_UNSPEC),因此可以使用任一常量。

下表列出了地址系列的公共值,尽管可能有多个其他值。

价值 意义
AF_UNSPEC
0
未指定地址系列。
AF_INET
2
Internet 协议版本 4 (IPv4) 地址系列。
AF_NETBIOS
17
NetBIOS 地址系列。 仅当安装了适用于 NetBIOS 的 Windows 套接字提供程序时,才支持此地址系列。
AF_INET6
23
Internet 协议版本 6 (IPv6) 地址系列。
AF_IRDA
26
红外数据关联(IrDA)地址系列。 仅当计算机安装了红外端口和驱动程序时,才支持此地址系列。
AF_BTH
32
蓝牙地址系列。 仅当蓝牙适配器安装在 Windows Server 2003 或更高版本上时,才支持此地址系列。

ai_socktype

类型:int

套接字类型。 套接字类型的可能值在 Winsock2.h include 文件中定义。

下表列出了 Windows 套接字 2 支持的套接字类型的可能值:

价值 意义
SOCK_STREAM
1
使用 OOB 数据传输机制提供基于连接的有序双向字节流。 将传输控制协议(TCP)用于 Internet 地址系列(AF_INETAF_INET6)。 如果 ai_family 成员 AF_IRDA,则 SOCK_STREAM 是唯一受支持的套接字类型。
SOCK_DGRAM
2
支持数据报,这些数据报是固定(通常较小)最大长度的无连接、不可靠的缓冲区。 将用户数据报协议(UDP)用于 Internet 地址系列(AF_INETAF_INET6)。
SOCK_RAW
3
提供一个原始套接字,允许应用程序作下一层协议标头。 若要作 IPv4 标头,必须在套接字上设置 IP_HDRINCL 套接字选项。 若要作 IPv6 标头,必须在套接字上设置 IPV6_HDRINCL 套接字选项。
SOCK_RDM
4
提供可靠的消息数据报。 此类型的一个示例是 Windows 中的实用常规多播(PGM)多播协议实现,通常称为 可靠的多播编程
SOCK_SEQPACKET
5
提供基于数据报的伪流数据包。
 

在 Windows 套接字 2 中,引入了新的套接字类型。 应用程序可以通过 WSAEnumProtocols 函数动态发现每个可用传输协议的属性。 因此,应用程序可以确定地址系列可能的套接字类型和协议选项,并在指定此参数时使用此信息。 Winsock2.hWs2def.h 头文件中的套接字类型定义将定期更新,因为定义了新的套接字类型、地址系列和协议。

在 Windows 套接字 1.1 中,唯一可能的套接字类型是 SOCK_DATAGRAMSOCK_STREAM

ai_protocol

类型:int

协议类型。 可能的选项特定于指定的地址系列和套接字类型。 Winsock2.hWsrm.h 头文件中定义了 ai_protocol 的可能值。

在适用于 Windows Vista 及更高版本的 Windows SDK 上,头文件的组织已更改,此成员可以是 Ws2def.h 头文件中定义的 IPPROTO 枚举类型之一。 请注意,Ws2def.h 头文件自动包含在 Winsock2.h中,不应直接使用。

如果为 ai_protocol指定了 0 值,则调用方不希望指定协议,服务提供商将选择要使用的 ai_protocol。 对于 IPv4 和 IPv6 以外的协议,请将 ai_protocol 设置为零。

下表列出了 ai_protocol 成员的常见值,尽管可能有多个其他值。

价值 意义
IPPROTO_TCP
6
传输控制协议 (TCP)。 当 ai_family 成员 AF_INETAF_INET6ai_socktype 成员 SOCK_STREAM时,此值是可能的。
IPPROTO_UDP
17
用户数据报协议(UDP)。 当 ai_family 成员 AF_INETAF_INET6类型 参数 SOCK_DGRAM时,此值是可能的。
IPPROTO_RM
113
可靠多播的 PGM 协议。 当 ai_family 成员 AF_INETai_socktype 成员 SOCK_RDM时,此值是可能的。 在适用于 Windows Vista 及更高版本的 Windows SDK 上,此值也称为 IPPROTO_PGM
 

如果 ai_family 成员 AF_IRDA,则 ai_protocol 必须为 0。

ai_addrlen

类型:size_t

ai_addr 成员指向的缓冲区的长度(以字节为单位)。

ai_canonname

类型:PCTSTR

主机的规范名称。

ai_addr

类型:结构 sockaddr*

指向 sockaddr 结构的指针。 每个返回 addrinfoex 结构中的 ai_addr 成员指向填充的套接字地址结构。 ai_addrlen 成员中指定了每个返回 addrinfoex 结构的长度(以字节为单位)。

ai_blob

类型:void*

指向用于返回与地址列表以外的名称关联的特定于提供程序的命名空间信息的数据的指针。 ai_blob 指向的缓冲区的长度(以字节为单位)必须在 ai_bloblen 成员中指定。

ai_bloblen

类型:size_t

ai_blob 成员的长度(以字节为单位)。

ai_provider

类型:LPGUID

指向特定命名空间提供程序 GUID 的指针。

ai_next

类型:结构 addrinfoex*

指向链接列表中的下一个结构的指针。 此参数设置为在链接列表的最后一 addrinfoex 结构中 NULL

言论

GetAddrInfoEx 函数使用 addrinfoex 结构来保存主机地址信息。 addrinfoex 结构的addrinfoaddrinfoW 结构的增强版本。 额外的结构成员用于 Blob 数据和命名空间提供程序的 GUID。 Blob 数据用于返回与名称关联的其他特定于提供程序的命名空间信息。 ai_blob 成员中的数据格式特定于特定的命名空间提供程序。 目前,NS_EMAIL 命名空间提供程序使用 blob 数据来提供其他信息。

addrinfoex 结构是 addrinfoaddrinfoW 结构的增强版本,用于 GetAddrInfoEx 函数。 GetAddrInfoEx 函数允许指定命名空间提供程序解析查询。 若要与 IPv6 和 IPv4 协议一起使用,名称解析可以由域名系统(DNS)、本地 主机 文件、电子邮件提供程序(NS_EMAIL 命名空间)或其他命名机制使用。

定义 UNICODE 或_UNICODE时,addrinfoex 定义为 addrinfoexW,即此结构的 Unicode 版本。 字符串参数定义为 PWSTR 数据类型,并使用 addrinfoexW 结构。

如果未定义 UNICODE 或_UNICODE,addrinfoex 定义为 addrinfoexA,即此结构的 ANSI 版本。 字符串参数是 PCSTR 数据类型,并且使用了 addrinfoexA 结构。

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

例子

以下示例演示如何使用 addrinfoex 结构。


#ifndef UNICODE
#define UNICODE
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

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

#pragma comment(lib, "Ws2_32.lib")

int __cdecl wmain(int argc, wchar_t ** argv)
{
//--------------------------------
// Declare and initialize variables.
    WSADATA wsaData;
    int iResult;

    ADDRINFOEX *result = NULL;
    ADDRINFOEX *ptr = NULL;
    ADDRINFOEX hints;

    DWORD dwRetval = 0;
    int i = 1;

    DWORD dwNamespace = NS_DNS;
    LPGUID lpNspid = NULL;

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

    wchar_t ipstringbuffer[46];

    // Validate the parameters
    if (argc != 3) {
        wprintf(L"usage: %ws <hostname> <servicename>\n", argv[0]);
        wprintf(L"       provides protocol-independent translation\n");
        wprintf(L"       from a host name to an IP address\n");
        wprintf(L"%ws example usage\n", argv[0]);
        wprintf(L"   %ws www.contoso.com 0\n", argv[0]);
        return 1;
    }
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed: %d\n", iResult);
        return 1;
    }
//--------------------------------
// Setup the hints address info structure
// which is passed to the GetAddrInfoW() function
    memset(&hints, 0, sizeof (hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    wprintf(L"Calling GetAddrInfoEx with following parameters:\n");
    wprintf(L"\tName = %ws\n", argv[1]);
    wprintf(L"\tServiceName (or port) = %ws\n\n", argv[2]);

//--------------------------------
// Call GetAddrInfoEx(). If the call succeeds,
// the aiList variable will hold a linked list
// of ADDRINFOEX structures containing response
// information about the host
    dwRetval = GetAddrInfoEx(argv[1], argv[2],
                             dwNamespace, lpNspid, &hints, &result,
                             NULL, NULL, NULL, NULL);

    if (dwRetval != 0) {
        wprintf(L"GetAddrInfoEx failed with error: %d\n", dwRetval);
        WSACleanup();
        return 1;
    }
    wprintf(L"GetAddrInfoEx returned success\n");

    // Retrieve each address and print out the hex bytes
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {

        wprintf(L"GetAddrInfoEx response %d\n", i++);
        wprintf(L"\tFlags: 0x%x\n", ptr->ai_flags);
        wprintf(L"\tFamily: ");
        switch (ptr->ai_family) {
        case AF_UNSPEC:
            wprintf(L"Unspecified\n");
            break;
        case AF_INET:
            wprintf(L"AF_INET (IPv4)\n");
            // the InetNtop function is available on Windows Vista and later
            sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
            wprintf(L"\tIPv4 address %ws\n",
                    InetNtop(AF_INET, &sockaddr_ipv4->sin_addr, ipstringbuffer,
                             46));

            // We could also use the WSAAddressToString function
            // 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)
            //    wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
            // else    
            //    wprintf(L"\tIPv4 address %ws\n", ipstringbuffer);
            break;
        case AF_INET6:
            wprintf(L"AF_INET6 (IPv6)\n");
            // the InetNtop function is available on Windows Vista and later
            sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
            wprintf(L"\tIPv6 address %ws\n",
                    InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr,
                             ipstringbuffer, 46));

            // We could also use WSAAddressToString which also returns the scope ID
            // 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)
            //    wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
            //else    
            //    wprintf(L"\tIPv6 address %ws\n", ipstringbuffer);
            break;
        default:
            wprintf(L"Other %ld\n", ptr->ai_family);
            break;
        }
        wprintf(L"\tSocket type: ");
        switch (ptr->ai_socktype) {
        case 0:
            wprintf(L"Unspecified\n");
            break;
        case SOCK_STREAM:
            wprintf(L"SOCK_STREAM (stream)\n");
            break;
        case SOCK_DGRAM:
            wprintf(L"SOCK_DGRAM (datagram) \n");
            break;
        case SOCK_RAW:
            wprintf(L"SOCK_RAW (raw) \n");
            break;
        case SOCK_RDM:
            wprintf(L"SOCK_RDM (reliable message datagram)\n");
            break;
        case SOCK_SEQPACKET:
            wprintf(L"SOCK_SEQPACKET (pseudo-stream packet)\n");
            break;
        default:
            wprintf(L"Other %ld\n", ptr->ai_socktype);
            break;
        }
        wprintf(L"\tProtocol: ");
        switch (ptr->ai_protocol) {
        case 0:
            wprintf(L"Unspecified\n");
            break;
        case IPPROTO_TCP:
            wprintf(L"IPPROTO_TCP (TCP)\n");
            break;
        case IPPROTO_UDP:
            wprintf(L"IPPROTO_UDP (UDP) \n");
            break;
        default:
            wprintf(L"Other %ld\n", ptr->ai_protocol);
            break;
        }
        wprintf(L"\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
        wprintf(L"\tCanonical name: %s\n", ptr->ai_canonname);
    }

    FreeAddrInfoEx(result);
    WSACleanup();

    return 0;
}


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

要求

要求 价值
最低支持的客户端 Windows Vista [仅限桌面应用]
支持的最低服务器 Windows Server 2008 [仅限桌面应用]
标头 ws2def.h (包括 Windows Server 2012、Windows 7 Windows Server 2008 R2)

另请参阅

GetAddrInfoEx

addrinfo

addrinfoW