getaddrinfo() 是唯一跨平台、支持双栈且能一次性获取全部 IP 地址的可靠接口;需设 hints.ai_family 为 AF_UNSPEC 并启用 AI_ALL 标志,socktype 设为 0,结果用 freeaddrinfo() 释放。

getaddrinfo() 是唯一可靠的选择
用 gethostbyname() 或手动解析 DNS 响应来拿全部 IP 已经不现实:前者已被废弃且不支持 IPv6,后者要自己处理 DNS 协议、超时、重试、EDNS 等,实际项目中没人这么干。标准库里唯一跨平台、支持双栈(IPv4/IPv6)、能一次拿到所有地址的接口就是 getaddrinfo()。
它返回的是链表结构的 addrinfo,每个节点对应一个可用地址(可能含不同协议族、不同套接字类型、不同优先级),不是简单“一个域名 → 一个 IP”。
常见错误现象:getaddrinfo() 返回成功但只拿到一个地址;或程序在 Linux 下正常,Windows 下卡住 —— 多半是没设对 hints.ai_family 或漏了 AI_ALL 标志。
- 必须把
hints.ai_family设为AF_UNSPEC,否则默认只查 IPv4 - 想确保 IPv4 和 IPv6 都返回(即使某类暂时不可用),加
AI_ALL标志 -
hints.ai_socktype设为SOCK_STREAM或SOCK_DGRAM会影响结果(比如某些 CDN 只对 TCP 提供 AAAA 记录),查地址列表建议设为0 - 调用后必须用
freeaddrinfo()释放内存,否则泄漏
完整示例:获取并打印所有 IPv4/IPv6 地址
下面这段代码会输出类似 142.250.191.46、2a00:1450:4001:82b::200e 这样的地址字符串:
#include <netdb.h>
#include <sys>
#include <arpa>
#include <iostream>
#include <<vector>std::vector<:string> resolve_all_ips(const char<em> hostname) {
struct addrinfo hints = {}, </em>result = nullptr;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_ALL | AI_ADDRCONFIG;<pre class="brush:php;toolbar:false;">int ret = getaddrinfo(hostname, nullptr, &hints, &result);
if (ret != 0) {
std::cerr ips;
for (struct addrinfo* rp = result; rp != nullptr; rp = rp->ai_next) {
char ipstr[INET6_ADDRSTRLEN];
void* addr;
size_t addr_len;
if (rp->ai_family == AF_INET) {
addr = &((struct sockaddr_in*)rp->ai_addr)->sin_addr;
addr_len = sizeof(struct in_addr);
} else if (rp->ai_family == AF_INET6) {
addr = &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr;
addr_len = sizeof(struct in6_addr);
} else {
continue;
}
if (inet_ntop(rp->ai_family, addr, ipstr, addr_len) != nullptr) {
ips.push_back(ipstr);
}
}
freeaddrinfo(result);
return ips;
}
注意:AI_ADDRCONFIG 表示“只返回本机已配置的协议族地址”,如果机器没启用 IPv6,就不会返回 AAAA 记录 —— 这是合理行为,不是 bug。测试时别用纯 IPv6-only 的域名去验证 IPv4 路径。
为什么 getaddrinfo() 返回的地址顺序不固定?
Linux 默认按 RFC 6724 规则排序(比如本地链路地址优先、相同前缀优先),glibc 还可能受 /etc/gai.conf 影响;Windows 则有自己的策略。你不能依赖返回顺序代表“最快”或“推荐使用”。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
常见误操作:取第一个地址就 connect,结果连上的是慢速节点或被墙 IP。真实项目中应该并发尝试多个地址,或结合 getnameinfo() + TTL + ping/HTTP head 做健康探测后再选。
- 不要假设
result链表头节点就是最优解 - 同一域名多次调用
getaddrinfo(),结果顺序可能不同(尤其开了 DNS 缓存或负载均衡) - 某些 DNS 服务(如 Cloudflare)会按客户端地理位置返回不同 IP 列表,这不是客户端问题
Windows 上需要额外链接 ws2_32.lib
否则链接时报错 unresolved external symbol getaddrinfo。MSVC 下需在项目设置里添加,或代码开头加:
#ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") #endif </ws2tcpip.h></winsock2.h>
而且 Windows 要求先调用 WSAStartup() 才能用网络 API —— 但 getaddrinfo() 是个例外:它在 Windows Vista+ 上是纯用户态实现,不需要初始化 Winsock。不过如果你后续要用 socket/connect,还是得初始化。
容易忽略的一点:Windows 的 getaddrinfo() 在某些旧版系统(XP SP2 以前)不支持 AI_ALL,返回 IPv6 地址可能失败。生产环境若需兼容 XP,得 fallback 到两次调用(分别查 AF_INET 和 AF_INET6)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










