getaddrinfo 是现代 DNS 解析首选接口,支持 IPv4/IPv6、线程安全、封装地址族适配与端口解析;需配对 freeaddrinfo,正确设置 hints(如 AF_UNSPEC、SOCK_STREAM)、避免空 hostname 或 Windows 未初始化 Winsock。

getaddrinfo 是 C++ 做 DNS 解析的首选接口
直接用 getaddrinfo,别碰过时的 gethostbyname。后者只支持 IPv4、不线程安全、无法指定协议族,现代代码里基本等于埋雷。
它封装了 DNS 查询 + 地址族适配(IPv4/IPv6)+ 端口解析,返回的是 addrinfo 链表,可直接喂给 socket 和 connect。
-
getaddrinfo是 POSIX 标准,Linux/macOS/Windows(通过ws2_32.lib)都支持 - 必须配对调用
freeaddrinfo,否则内存泄漏(链表节点是 malloc 出来的) - 传
nullptr作为 hostname 时,会返回本地通配地址(INADDR_ANY或::),不是 DNS 查询 - 错误码在返回值里(
int),不是errno;失败时用gai_strerror转成字符串
如何正确填参避免返回空结果或 EAI_NONAME
常见错误是把 hints 设得太严,比如硬写 ai_family = AF_INET 却查一个只支持 IPv6 的域名(如 ipv6.google.com),或者漏设 ai_socktype 导致匹配不到记录。
建议最小化约束:只设 ai_family = AF_UNSPEC(让系统自己选)、ai_socktype = SOCK_STREAM(或 SOCK_DGRAM),其余字段清零。
立即学习“C++免费学习笔记(深入)”;
-
ai_flags加AI_ADDRCONFIG可避免查到本地没启用的地址族(例如没配 IPv6 时忽略 AAAA 记录) - 端口号传字符串(
"80")比整数更安全,getaddrinfo会自动查/etc/services或 fallback 到数值 - hostname 不能为空字符串,也不能含端口(如
"example.com:80"),会直接返回EAI_NONAME
Windows 上必须初始化 Winsock 才能调用 getaddrinfo
Linux/macOS 没这回事,但 Windows 下漏掉 WSAStartup 会导致 getaddrinfo 返回 EAI_SYSTEM,WSAGetLastError() 是 WSANOTINITIALISED —— 这个错不看文档根本猜不到。
- 只需调一次
WSAStartup(MAKEWORD(2,2), &wsaData),通常放在 main 开头 - 对应要调
WSACleanup(),但进程退出前不调一般也不崩(只是严格意义上资源未释放) - 链接时加
-lws2_32(GCC)或确保项目配置了ws2_32.lib(MSVC)
异步或超时控制得靠自己封装
getaddrinfo 是阻塞的,且没有内置超时。DNS 查询卡住几秒很常见(尤其网络异常或递归服务器无响应),不能让它拖垮整个连接流程。
标准库没提供异步替代,得自己处理:
- 开独立线程跑
getaddrinfo,主线程用std::thread::join_for或条件变量带超时等待 - 用
poll/select对 UDP socket(如果自己发 DNS 包)做超时,但那就不是用getaddrinfo了 - 某些场景下可先查缓存(如
getaddrinfo结果缓存几秒),但注意 TTL 和并发修改问题
真正难的不是调用函数,而是处理它返回的 addrinfo 链表——不同记录顺序、AI_CANONNAME 是否存在、是否要尝试多个地址连通性,这些逻辑远比解析本身复杂。


















