C 编程/POSIX 参考/netdb.h/getaddrinfo
getaddrinfo()
和 getnameinfo()
函数是 POSIX 标准应用程序编程接口 (API) 的一部分,用于在域名系统 (DNS) 主机名和 IP 地址之间转换其人类可读的文本表示形式和操作系统网络 API 的结构化二进制格式。
getaddrinfo()和getnameinfo()是彼此的逆函数。
这套函数完全独立于网络协议,支持 IPv4 和 IPv6。它是构建独立于协议的应用程序和将旧版 IPv4 代码迁移到 IPv6 互联网中进行名称解析的推荐接口。
用于在网络 API 中表示地址和主机名的 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; /* canonical name */
struct addrinfo *ai_next; /* this struct can form a linked list */
};
在最近的操作系统中,ai_addrlen 的类型已从 size_t 更改为 socklen_t。大多数套接字函数(如 accept 和 getpeername)需要 socklen_t* 参数,程序员经常将地址传递给 addrinfo 结构的 ai_addrlen 元素。如果类型不兼容,例如在 size_t 为 8 字节而 socklen_t 为 4 字节的大端 64 位 Solaris 9 系统上,则可能会导致运行时错误。
getaddrinfo()将表示主机名或 IP 地址的人类可读文本字符串转换为动态分配的struct addrinfo结构的链表。应用程序可以使用freeaddrinfo()函数释放这些链表。这些函数的函数原型指定如下
#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);
void freeaddrinfo(struct addrinfo *res);
getnameinfo()将struct sockaddr指针形式的 IP 地址的内部二进制表示形式转换为文本字符串,该字符串包含主机名或(如果地址无法解析为名称)文本 IP 地址表示形式,以及服务端口名称或编号。函数原型指定如下
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen,
int flags);
以下示例使用getaddrinfo()将域名 www.example.com 解析为其地址列表,然后调用getnameinfo()在每个结果上返回该地址的规范名称。通常,这将生成原始主机名,除非特定地址具有多个名称,在这种情况下,将返回规范名称。在此示例中,域名将打印三次,每次都对应于获得的三个结果之一。
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
int main(void)
{
struct addrinfo *result;
struct addrinfo *res;
int error;
/* resolve the domain name into a list of addresses */
error = getaddrinfo("www.example.com", NULL, NULL, &result);
if (error != 0)
{
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
return EXIT_FAILURE;
}
/* loop over all returned results and do inverse lookup */
for (res = result; res != NULL; res = res->ai_next)
{
char hostname[NI_MAXHOST] = "";
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
if (error != 0)
{
fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
continue;
}
if (*hostname != '\0')
printf("hostname: %s\n", hostname);
}
freeaddrinfo(result);
return EXIT_SUCCESS;
}
- RFC 3493,IPv6 的基本套接字接口扩展