🤖
Ai回答
`getaddrinfo` 是一个用于域名解析的通用函数,属于 POSIX 标准 API,支持 IPv4 和 IPv6,能够将主机名(域名)转换为 IP 地址,或反之(反向解析)。以下是其核心要点和用法:
函数原型
c
include <sys/types.h
include <sys/socket.h
include <netdb.h
int getaddrinfo(
const char *node, // 主机名或IP字符串(如 example.com)
const char *service, // 服务名或端口号(如 http 或 80)
const struct addrinfo *hints, // 过滤条件(如协议类型)
struct addrinfo res // 返回结果的链表
);
void freeaddrinfo(struct addrinfo *res); // 释放结果内存
关键参数
1、`node`
要解析的域名(如 `google.com`),或直接传入 IP 字符串(如 `192.0.2.1`)。
若为 `NULL`,返回的地址会绑定到本地所有接口(如 `0.0.0.0` 或 `::`)。
2、`service`
服务名称(如 `http`)或端口号字符串(如 `80`)。
若不需要端口信息,可设为 `NULL`。
3、`hints`
指定返回结果的过滤条件(如协议类型、Socket 类型等)。
常用字段:
c
struct addrinfo hints = {
.ai_family = AF_UNSPEC, // IPv4/IPv6 均可(AF_INET 或 AF_INET6 限制其一)
.ai_socktype = SOCK_STREAM, // 流式 Socket(TCP)
.ai_flags = AI_PASSIVE // 用于服务器绑定本地地址
};
4、`res`
返回一个链表,包含所有可能的地址信息(需用 `freeaddrinfo` 释放)。
返回值
成功:返回 `0`,结果存储在 `res` 中。
失败:返回非零错误码(用 `gai_strerror()` 转换为可读字符串)。
基本流程
1、初始化 `hints`:指定需要的地址类型。
2、调用 `getaddrinfo`:传入域名和服务信息。
3、遍历结果链表:获取所有可能的 IP 地址。
4、释放资源:使用 `freeaddrinfo`。
示例代码(解析域名)
c
include <stdio.h
include <netdb.h
include <arpa/inet.h
int main() {
struct addrinfo hints = {0}, *res, *p;
hints.ai_family = AF_UNSPEC; // IPv4 或 IPv6
hints.ai_socktype = SOCK_STREAM; // TCP
int status = getaddrinfo(example.com, 80, &hints, &res);
if (status != 0) {
fprintf(stderr, getaddrinfo error: %s\n, gai_strerror(status));
return 1;
}
// 遍历所有结果
for (p = res; p != NULL; p = pai_next) {
char ipstr[INET6_ADDRSTRLEN];
void *addr;
if (pai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)pai_addr;
addr = &(ipv4sin_addr);
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)pai_addr;
addr = &(ipv6sin6_addr);
}
inet_ntop(pai_family, addr, ipstr, sizeof(ipstr));
printf(IP: %s\n, ipstr);
}
freeaddrinfo(res); // 释放内存
return 0;
}
常见用途
1、客户端连接服务器:解析域名获取 IP 地址列表,逐个尝试连接。
2、服务器绑定监听:通过 `AI_PASSIVE` 标志获取本地地址。
3、协议无关编程:统一处理 IPv4 和 IPv6。
注意事项
错误处理:检查返回值,使用 `gai_strerror` 输出错误信息。
内存管理:必须调用 `freeaddrinfo` 释放结果链表。
超时控制:默认无超时机制,需自行实现(如信号或线程取消)。
反向解析(IP 转域名)**
使用 `getnameinfo` 函数:
c
char host[NI_MAXHOST];
getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NAMEREQD);
通过掌握 `getaddrinfo`,可以实现灵活、跨协议的地址解析。