getaddrinfo() 函数用于网络地址和服务转换,其原型声明如下:
[C++] 纯文本查看 复制代码 #include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
第 1 个参数 node 是一个主机名或地址串( IPv4 的点分十进制或 IPv6 十六进制数串 )。
第 2 个参数 service 是一个服务名或十进制端口号数串。
第 3 个参数 hints 是一个 struct addrinfo 结构的指针(也可以为空)。如果该指针非空时,可以在所指向的结构中填入期望返回的信息类型的暗示。比如说,如果指定的服务既支持 TCP 也支持 UDP,如果我们希望返回的只是 UDP 的信息,那么可以将 hints 结构中的 ai_socktype 成员设置为 SOCK_DGRAM 。struct addrinfo 结构定义如下:
[C++] 纯文本查看 复制代码 struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
其中,
ai_family : 该成员指定期望返回的地址族,比如 AF_INET 或 AF_INET6 。如果指定为 AF_UNSPEC (宏定义中,该值为 0)那么表示让函数返回所有可能的地址族,即可以是 IPv4 或者是 IPv6 。
ai_socktype : 该成员指出 socket 类型,比如 SOCK_STREAM 或者 SOCK_DGRAM 。如果指定为 0,那么函数返回所有可能的类型。
ai_protocol : 该成员指定协议,0 或者 IPPROTO_xxx (IPPROTO_ICMP, IPPROTO_TCP 等) 。如果指定为 0,那么函数返回所有可能的类型。
ai_flags : 该成员提供额外的选项,有多个可用标志值,这些标志可用或符号结合起来,这些标志值有:
AI_PASSIVE : 套接字将用于被动打开。
AI_CANONNAME : 让 getaddrinfo() 返回主机的规范名 。
AI_NUMERICHOST : 此时 node 参数必须是一个地址串,该标志用以防止任何类型的名字到地址映射,也就是说不需要进行从网址到 IP 的 DNS 查询。
AI_NUMERICSERV : 此时 service 参数必须是一个十进制端口号数串,该标志用以防止任何类型的名字到服务映射,也就是说只需根据端口号就能查到相应的服务名(gethostbyport() 函数) 。
AI_V4MAPPED : 如果同时指定了 ai_family 成员的值为 AF_INET6,那么如果没有可用的 AAAA 记录( IPv4 在 DNS 里用的是 A 记录,一个 A 记录把一个主机名映射成一个 32 位的 IPv4 地址;而 AAAA 记录把一个主机名映射成一个 128 位的 IPv6 地址,因此 “四A” 的意思就是 128 位是 32 位的 4 倍),那么就返回 A 记录对应的 IPv4 记录对应的 IPv4 映射的 IPv6 地址(参考:IPv6 记法 )。
AI_ALL : 如果同时指定 AI_V4MAPPED 标志,那么除了返回与 AAAA 记录对应的 IPv6 地址外,还返回与 A 记录对应的 IPv4 映射的 IPv6 地址。
AI_ADDRCONFIG : 按照所在主机的配置选择返回地址类型。如果主机上有一个或多个接口(除了 lookback 接口外) 时,查找其它配置的地址类型(IPv4 和 IPv6) 。
第 4 个参数 res 是个 struct addrinfo 结构指针的指针。getaddrinfo() 函数会将返回的信息存储在它动态分配的内存空间里,这些空间是由一个 struct addrinfo 结构的单向链表所占据,链表中的每个结构由 ai_next 成员指针所连接。
测试代码:
[C++] 纯文本查看 复制代码 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int
lookup_host (const char *host)
{
struct addrinfo hints, *res;
int errcode;
char addrstr[100];
void *ptr;
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
errcode = getaddrinfo (host, NULL, &hints, &res);
if (errcode != 0)
{
perror ("getaddrinfo");
return -1;
}
printf ("Host: %s\n", host);
while (res)
{
inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
switch (res->ai_family)
{
case AF_INET:
ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
break;
case AF_INET6:
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
break;
}
inet_ntop (res->ai_family, ptr, addrstr, 100);
printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4,
addrstr, res->ai_canonname);
res = res->ai_next;
}
return 0;
}
int
main (int argc, char *argv[])
{
if (argc < 2)
exit (1);
return lookup_host (argv[1]);
}
运行输出:# ./getaddrinfo www.groad.net
Host: www.groad.net
IPv4 address: 218.77.79.100 (lb.360wzb.com)
# ./getaddrinfo www.mobaoge.net
Host: www.mobaoge.net
IPv4 address: 59.57.12.38 (common.xgslb.net)
IPv4 address: 113.107.43.238 ((null)) |