设置 DNS 解析超时和重试
优质
小牛编辑
138浏览
2023-12-01
网络编程中经常使用gethostbyname
和getaddrinfo
来实现域名解析,这两个C
函数并未提供超时参数。实际上可以修改/etc/resolv.conf
来设置超时和重试逻辑。
!> 可参考man resolv.conf
文档
多个 NameServer
nameserver 192.168.1.3
nameserver 192.168.1.5
option rotate
可配置多个nameserver
,底层会自动轮询,在第一个nameserver
查询失败时会自动切换为第二个nameserver
进行重试。
option rotate
配置的作用是,进行nameserver
负载均衡,使用轮询模式。
超时控制
option timeout:1 attempts:2
timeout
:控制UDP
接收的超时时间,单位为秒,默认为5
秒attempts
:控制尝试的次数,配置为2
时表示,最多尝试2
次,默认为5
次
假设有2
个nameserver
,attempts
为2
,超时为1
,那么如果所有DNS
服务器无响应的情况下,最长等待时间为4
秒(2x2x1
)。
调用跟踪
可使用strace跟踪确认。
将nameserver
设置为两个不存在的IP
,PHP
代码使用var_dump(gethostbyname('www.baidu.com'));
解析域名。
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.20.128.16")}, 16) = 0
poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
sendto(3, "\346\5\1\0\0\1\0\0\0\0\0\0\3www\5baidu\3com\0\0\1\0\1", 31, MSG_NOSIGNAL, NULL, 0) = 31
poll([{fd=3, events=POLLIN}], 1, 1000
) = 0 (Timeout)
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.20.128.18")}, 16) = 0
poll([{fd=4, events=POLLOUT}], 1, 0) = 1 ([{fd=4, revents=POLLOUT}])
sendto(4, "\346\5\1\0\0\1\0\0\0\0\0\0\3www\5baidu\3com\0\0\1\0\1", 31, MSG_NOSIGNAL, NULL, 0) = 31
poll([{fd=4, events=POLLIN}], 1, 1000
) = 0 (Timeout)
poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
sendto(3, "\346\5\1\0\0\1\0\0\0\0\0\0\3www\5baidu\3com\0\0\1\0\1", 31, MSG_NOSIGNAL, NULL, 0) = 31
poll([{fd=3, events=POLLIN}], 1, 1000
) = 0 (Timeout)
poll([{fd=4, events=POLLOUT}], 1, 0) = 1 ([{fd=4, revents=POLLOUT}])
sendto(4, "\346\5\1\0\0\1\0\0\0\0\0\0\3www\5baidu\3com\0\0\1\0\1", 31, MSG_NOSIGNAL, NULL, 0) = 31
poll([{fd=4, events=POLLIN}], 1, 1000
) = 0 (Timeout)
close(3) = 0
close(4) = 0
可以看到这里一共重试了4
次,poll
调用超时设置为1000ms
(1秒
)。