C++如何实现简单的异步 DNS 解析请求器 (A/AAAA 记录)

老枫姑娘_5845

老枫姑娘_5845

2026-06-19

894人浏览

原创

不能直接用 getaddrinfo 做异步 dns 查询,因为它是阻塞的,会导致线程卡住;即使丢进线程池也属伪异步,无法取消、难集成事件循环、线程开销大。

c++如何实现简单的异步 dns 解析请求器 (a/aaaa 记录)

为什么不能直接用 getaddrinfo 做异步 DNS 查询

因为标准 C++ 没有内置异步 DNS API,而 getaddrinfo 是阻塞的 —— 它会卡住当前线程直到系统 resolver 返回结果(可能几百毫秒甚至超时)。哪怕你把它丢进线程池,也属于“伪异步”:无法取消、无法与 epoll/kqueue 集成、线程开销大,且在高并发场景下容易耗尽线程资源。

用 libuv + uv_getaddrinfo 实现真正异步解析

libuv 是 Node.js 底层跨平台异步 I/O 库,它封装了各系统原生异步 DNS 机制(Linux 上用 getaddrinfo_a 或线程池模拟,macOS/iOS 用 dns_service_create_query,Windows 用 GetAddrInfoEx),对外提供统一回调接口。关键优势是:可取消、无额外线程、能和 TCP/UDP 句柄共用同一个事件循环。

实操要点:

  • uv_getaddrinfo 的 hints.ai_family 设为 AF_UNSPEC 可同时请求 A 和 AAAA;设为 AF_INET 或 AF_INET6 则只查一种
  • 回调函数中必须调用 uv_freeaddrinfo 释放 addrinfo 链表,否则内存泄漏
  • 错误码通过 status 参数返回:UV_EAI_NONAME 表示域名不存在,UV_EAI_FAIL 表示 DNS 服务器拒绝或格式错误,不是网络超时
  • 超时需自行用 uv_timer_t 控制,uv_getaddrinfo 本身不支持 timeout 参数

简短示例(忽略初始化和 loop run):

void on_dns_resolve(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
  if (status == 0) {
    for (struct addrinfo* ai = res; ai; ai = ai->ai_next) {
      if (ai->ai_family == AF_INET) {
        char ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, ip, sizeof(ip));
        printf("A: %s\n", ip);
      } else if (ai->ai_family == AF_INET6) {
        char ip[INET6_ADDRSTRLEN];
        inet_ntop(AF_INET6, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, ip, sizeof(ip));
        printf("AAAA: %s\n", ip);
      }
    }
  } else {
    fprintf(stderr, "DNS resolve failed: %s\n", uv_strerror(status));
  }
  uv_freeaddrinfo(res); // 必须调用
  delete req; // req 是 new 出来的,此处释放
}

发起请求:

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
uv_getaddrinfo_t* req = new uv_getaddrinfo_t;
struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int r = uv_getaddrinfo(loop, req, on_dns_resolve, "example.com", nullptr, &hints);
if (r != 0) {
  fprintf(stderr, "uv_getaddrinfo error: %s\n", uv_strerror(r));
  delete req;
}

不用第三方库?std::thread + getaddrinfo 的安全封装要点

若项目禁止引入 libuv 或 Boost.Asio,只能用标准库,那必须自己管理线程+超时+取消。但注意:getaddrinfo 本身不可中断,所以“取消”实际是等待线程自然退出或超时后丢弃结果。

关键约束:

  • 每个查询必须独占一个 std::thread,不能复用线程(getaddrinfo 不是 reentrant 的)
  • 必须用 std::promise/std::future 传递结果,避免裸指针生命周期问题
  • std::thread::joinable() 要检查,防止重复 join 或忘记 join/detach
  • Linux 下建议设置 resolv.conf 中的 options timeout:1 attempts:2,否则默认可能等 5 秒

常见失败场景和调试线索

DNS 异步请求失败,90% 不是代码逻辑问题,而是环境或配置导致:

  • 查不到 AAAA 记录但 A 正常 → 检查本地 DNS 服务器是否支持 IPv6 解析(如 dig AAAA example.com @8.8.8.8)
  • UV_EAI_AGAIN 频繁出现 → 系统 resolver 负载高或 /etc/resolv.conf 配置了 unreachable nameserver
  • 同一域名反复解析变慢 → 检查是否未复用 uv_loop_t,每次新建 loop 会重载 resolver 配置
  • macOS 上返回空结果但无错误 → hints.ai_flags 忘加 AI_ADDRCONFIG,导致 IPv6 接口未启用时 AAAA 查询被静默跳过

真正难处理的是 resolver 层的中间状态:超时、截断、重试策略、EDNS0 支持与否 —— 这些都藏在系统库背后,异步封装层只能暴露结果和粗粒度错误码,细节日志得靠 tcpdump -i any port 53 抓包确认。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++ dns

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2248

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1019

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

427

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

327

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

406

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

580

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1409

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1217

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习