getaddrinfo_a是linux glibc提供的轻量级异步dns查询接口,支持批量解析a/aaaa记录,需配合轮询gai_error或gai_suspend等待完成,不提供内置超时,须自行实现,且必须链接-lanl库。

用 getaddrinfo_a 发起异步 DNS 查询(Linux)
Linux 提供了 GNU 扩展的异步解析接口 getaddrinfo_a,它不阻塞线程,适合轻量级异步场景。但注意:它不是 POSIX 标准,仅 glibc 支持,且必须配合 sigwait 或 aiocb 机制轮询/等待完成——它本身不启动线程或回调。
常见错误是直接调用后立刻读 gai_error,结果总是 EAI_INPROGRESS;实际需用 aio_suspend 等待,或轮询 gai_error 字段(需确保内存对齐和可见性)。
- 必须用
struct gaicb*数组传入,每个元素含ar_name(域名)、ar_service(端口)、ar_request(addrinfo模板) - 调用前设
ar_request.ai_flags = AI_ADDRCONFIG避免 IPv6-only 环境查 IPv4 失败 -
aio_suspend的 timeout 参数建议设为非 NULL,否则可能永久挂起(尤其在信号被屏蔽时) - 返回的
struct addrinfo*必须用freeaddrinfo释放,不能delete或free
本地缓存用 std::unordered_map + TTL 控制(无锁简化版)
缓存核心矛盾是「一致性」和「性能」:加锁安全但影响并发吞吐;不加锁又怕读到中间态。简单项目可接受「缓存过期后首次查询更新」策略,用 std::unordered_map<:string std::pair>, time_t>></:string> 存域名→地址列表+过期时间。
别直接存 addrinfo*:生命周期难管理,且不同调用间 ai_addr 内存布局可能变;转存为 sockaddr_storage 更可控。
免费 DNS 与邮件安全分析(IntoDNS.ai):包括 DNSSEC、SPF、DKIM、DMARC、MTA-STS、BIMI、SMTP STARTTLS、FCrDNS、黑名单、发件人要求及报告。
- TTL 建议取自 DNS 响应中的
ttl字段,若异步接口不提供(getaddrinfo_a确实不提供),则 fallback 到固定值如 300 秒 - 缓存查找前先检查
time(nullptr) > cached_time,过期即丢弃,不尝试刷新(避免查询风暴) - 插入缓存时用
try_emplace避免重复构造 value,尤其vector可能触发多次分配
Windows 上替代方案:用 GetAddrInfoEx + OVERLAPPED
Windows 没有 getaddrinfo_a,等效的是 GetAddrInfoEx 配合 I/O 完成端口或事件对象。它支持真正的异步(内核级),但 API 更重,且要求传入 LPOVERLAPPED 和回调函数(或手动 GetOverlappedResult)。
容易踩的坑是忘记初始化 OVERLAPPED 结构体:必须 ZeroMemory,且 hEvent 若用事件模式,需用 WSAEventSelect 关联 socket(但 DNS 不走 socket)——正确做法是创建手动重置事件,传入 hEvent 字段。
- 调用前必须先
WSAStartup,否则返回WSANOTINITIALISED -
dwFlags推荐加ADDRINFO_EX_FLAG_CACHE_ONLY测试缓存路径是否生效 - 返回的
ADDRINFOEXW*必须用FreeAddrInfoEx释放,freeaddrinfo会 crash - IPv6 地址字节序需手动用
ntohl/ntohs转换,sockaddr_in6.sin6_addr是网络序,直接打印会错
缓存失效与线程安全边界在哪
真正难处理的不是「怎么存」,而是「什么时候不该用缓存」。比如:程序运行中网络接口切换(WiFi → 以太网)、/etc/resolv.conf 被修改、或系统 DNS 缓存(systemd-resolved)重启——你的本地缓存对此毫无感知。
所以缓存只能作为「短周期加速」,不能替代真实解析。所有缓存条目必须带明确 TTL,且 TTL 到期后必须重新发起异步请求,而不是静默返回旧值。
- 不要把缓存逻辑塞进异步回调里:回调中做 map 插入 + 时间判断,易因异常中断导致状态不一致
- 如果多个线程共用一个缓存 map,至少对写操作加
std::shared_mutex(C++17),读多写少时比mutex更高效 - 测试时用
dig +short example.com @8.8.8.8对比 TTL,确认你代码里写的 300 秒和真实响应是否一致
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










