ADDRINFOA 结构 (ws2def.h)

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

语法

typedef struct addrinfo {
  int             ai_flags;
  int             ai_family;
  int             ai_socktype;
  int             ai_protocol;
  size_t          ai_addrlen;
  char            *ai_canonname;
  struct sockaddr *ai_addr;
  struct addrinfo *ai_next;
} ADDRINFOA, *PADDRINFOA;

成员

ai_flags

类型: int

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

ai_flags 成员的支持值在 Windows 7 及更高版本Windows SDK上的 Ws2def.h 头文件中定义。 这些值在 Windows Server 2008 和 Windows Vista Windows SDK上的 Ws2tcpip.h 头文件中定义。 这些值在适用于 Windows Server 2003 和 Windows XP 的平台 SDK 上的 Ws2tcpip.h 头文件中定义。 ai_flags 成员支持的值可以是以下选项的组合。

含义
AI_PASSIVE
0x01
套接字地址将用于对 绑定 函数的调用。
AI_CANONNAME
0x02
规范名称在第一 个ai_canonname 成员中返回。
AI_NUMERICHOST
0x04
传递给 getaddrinfo 函数的 nodename 参数必须是数值字符串。
AI_ALL
0x0100
如果设置了此位,则会对具有 AI_V4MAPPED的 IPv6 地址和 IPv4 地址发出请求。

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

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

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

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

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

AI_NON_AUTHORITATIVE
0x04000
地址信息可以来自非权威命名空间提供程序。

只有 Windows Vista 和更高版本的 NS_EMAIL 命名空间才支持此选项。

AI_SECURE
0x08000
地址信息来自安全通道。

只有 Windows Vista 和更高版本的 NS_EMAIL 命名空间才支持此选项。

AI_RETURN_PREFERRED_NAMES
0x010000
地址信息是用户的首选名称。

只有 Windows Vista 和更高版本的 NS_EMAIL 命名空间才支持此选项。

AI_FQDN
0x00020000
如果指定了一个平面名称 (单个标签) , 则 getaddrinfo 将返回该名称最终解析为的完全限定域名。 完全限定的域名在 ai_canonname 成员中返回。

这与返回 DNS 中注册的规范名称 AI_CANONNAME 位标志不同,该标志可能与平面名称解析为的完全限定域名不同。

只能设置 AI_FQDN 位和 AI_CANONNAME 位中的一个。 如果两个标志都带有EAI_BADFLAGS则 getaddrinfo 函数将失败。

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

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

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

ai_family

类型: int

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

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

当前支持的值 是 AF_INETAF_INET6,它们是 IPv4 和 IPv6 的 Internet 地址系列格式。 AF_NETBIOS用于 NetBIOS 的地址系列 ( 的其他选项,例如,如果安装了地址系列的 Windows 套接字服务提供商,则支持) 。 请注意,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 (IrDA) 地址系列。 仅当计算机安装了红外端口和驱动程序时,才支持此地址系列。
AF_BTH
32
蓝牙地址系列。 仅当在 Windows Server 2003 或更高版本上安装蓝牙适配器时,才支持此地址系列。

ai_socktype

类型: int

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

下表列出了 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

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

在 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_INET或AF_INET6ai_socktype成员SOCK_STREAM时,此值是可能的
IPPROTO_UDP
17
用户数据报协议 (UDP) 。 当ai_family成员AF_INET或AF_INET6类型参数SOCK_DGRAM时,此值可能为
IPPROTO_RM
113
可靠多播的 PGM 协议。 当ai_family成员AF_INET且ai_socktype成员为SOCK_RDM时,此值是可能的。 在 Windows Vista 及更高版本发布的Windows SDK中,此值也称为IPPROTO_PGM
 

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

ai_addrlen

类型: size_t

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

ai_canonname

类型: char*

主机的规范名称。

ai_addr

类型: struct sockaddr*

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

ai_next

类型: struct addrinfo*

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

注解

ANSI getaddrinfo 函数使用 addrinfo 结构来保存主机地址信息。

addrinfoW 结构是 Unicode GetAddrInfoW 函数使用的此结构的版本。

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

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

在较旧版本的 Windows 上支持 getaddrinfo 和 addrinfo 结构

使用 addrinfo 结构的 getaddrinfo 函数已添加到 Windows XP 及更高版本的 Ws2_32.dlladdrinfo 结构在 Ws2tcpip.h 头文件中定义,该文件包含在适用于 Windows XP 及更高版本的平台 SDK 中,Windows SDK为 Windows Vista 及更高版本发布。

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

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

使用 addrinfoW 结构的 GetAddrInfoW 函数是 getaddrinfo 函数和关联的 addrinfo 结构的 Unicode 版本。 GetAddrInfoW 函数已添加到 Windows XP 中的 Ws2_32.dll,Service Pack 2 (SP2) 。 GetAddrInfoW 函数和 addrinfoW 结构不能在早于 SP2 的 Windows XP 版本上使用。

示例

下面的代码示例演示如何使用 addrinfo 结构。


#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("       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;
}

要求

要求
最低受支持的客户端 Windows 2000 Professional [仅限桌面应用]
最低受支持的服务器 Windows 2000 Server [仅限桌面应用]
标头 ws2def.h

另请参阅

GetAddrInfoW

WSAEnumProtocols

addrinfoW

bind

getaddrinfo

sockaddr