在编写网络客户端时,域名解析(DNS)往往是一个被忽视的性能杀手。标准的
getaddrinfo 或 gethostbyname
是同步阻塞的。如果 DNS 服务器响应慢,你的
Event Loop 就会卡住,导致所有连接超时。
Libevent 提供了 evdns 模块,实现了完全异步的
DNS 解析器。
1. 为什么需要 evdns?
- 非阻塞: 发起查询后立即返回,解析完成后回调通知。
- 并发: 可以同时发起成千上万个 DNS 查询。
- 缓存: 内置了简单的 DNS 缓存,减少网络交互。
2. 基本用法
2.1. 初始化
#include <event2/dns.h>
struct evdns_base *dns_base = evdns_base_new(base, 1);
if (!dns_base) {
// handle error
}第二个参数 1 表示初始化默认的
nameservers(在 Linux 上读取
/etc/resolv.conf,在 Windows
上读取注册表)。
2.2. 发起查询
void dns_cb(int result, char type, int count, int ttl, void *addresses, void *arg) {
if (result != DNS_ERR_NONE) {
printf("DNS resolve failed: %s\n", evdns_err_to_string(result));
return;
}
if (type == DNS_IPv4_A) {
struct in_addr *addrs = (struct in_addr *)addresses;
for (int i = 0; i < count; ++i) {
char buf[64];
inet_ntop(AF_INET, &addrs[i], buf, sizeof(buf));
printf("IP: %s\n", buf);
}
}
}
// 查询 A 记录 (IPv4)
evdns_base_resolve_ipv4(dns_base, "www.google.com", 0, dns_cb, NULL);3. 高级特性
3.1. 自定义 Nameserver
你可以不使用系统的 DNS 配置,而是指定特定的 DNS 服务器(如 8.8.8.8)。
evdns_base_nameserver_ip_add(dns_base, "8.8.8.8");3.2. 搜索域 (Search Domains)
支持处理 /etc/resolv.conf 中的
search 指令,自动补全域名后缀。
4. 总结
在高性能网络编程中,永远不要在 Event Loop
中调用阻塞函数。DNS 解析是最大的隐患之一。使用
evdns,让你的程序在解析域名的同时,依然能流畅地处理成千上万个并发连接。
上一篇: 05-protocols/http-server.md - 内置 HTTP Server 下一篇: 05-protocols/modern-web.md - 现代 Web 协议集成