getaddrinfo return system error导致设备无法连接外网,DNS解析失败

一、现象:最近在设备上开发新功能,使用一份物联网设备端的SDK,出现了一个问题,设备从一个WiFi A切换到另一个WiFi  B,无法连接外网,导致和服务器的通讯失败

1、查看串口信息后发现异常时getaddrinfo返回system error;

2、问题出现时,在设备上使用ping命令,能够ping通外网;

3、每次从WiFi A切换到WiFi B都会出现相同的问题;

4、将设备从WiFi A切换到WiFi C,能够正常连接外网;

5、设备已经量产多年,以前未曾出现过这种问题;

6、设备切换路由器后,都有重启网络,对网络重新配置。

二、定位过程:

1、首先怀疑设备的WiFi切换过程后,获取到的DNS服务器地址有问题,将DNS主服务器配置为114.114.114.114,辅服务器地址为8.8.8.8,配置后,问题依旧能够复现,查看etc/resolv.conf文件,每次都能够正常更新;

2、怀疑相关的配置文件没有补充,查看了设备的配置文件目录,etc/hosts文件缺失,在该目录下配置该文件,设备依旧无法正常连接服务器;

3、更换getaddrinfo接口为gethostbyname,问题依旧存在;

4、由于问题出现时,能够正常使用ping命令ping通外网域名,ping命令也是通过getaddrinfo接口实现域名解析,参考ping命令的实现,将getaddtinfo接口传入参数设置和ping命令传入参数一致,问题依旧存在;

5、在ubuntu系统上,执行SDK,将ubuntu系统的WiFi从WiFi A切换到WiFi B,能够正常使用,可以排除SDK的问题;

6、在设备上导入tcpdump,抓取切换WiFi前后的数据变化,发现切换为WiFi B路由器之后,设备解析域名时,通过DNS请求域名的地址使用的DNS服务器是WiFi A的DNS服务器地址,找到了问题出现的直接原因,就是执行getaddrinfo时使用的DNS服务器地址不正确,而WiFi A和WiFi C的DNS地址一致,导致两个切换动作结果有区别。

三、问题解决

通过查找资料可知,getaddrinfo 第一次 执行时 会调用 res_init(),res_init() 初始化后,nameserver 地址被初始化到当前进程的 _res_ 结构体中, 然而 res_init() 对于每个进程来说,实际会使用 glibc 的相关函数,glibc 在应用第一次域名解析的时候会触发 res_init() 函数的调用,res_init() 函数的作用是读取 /etc/resolv.conf 的内容,,并将读取的这些数据放到 static 类型的 _res_ 结构体中。由于 Linux 的进程在使用 glibc 动态链接库全局静态变量的时候,都会在用户进程空间生成自己独立的变量副本,所以每个发起 DNS 解析的进程都具有独立的 _res_ 结构体变量。我的设备的进程只启动一次,进程启动后发起第一次域名解析请求,该请求最后会调用res_init() 执行一次。这就导致设备每次ping都能够正常,而切换WiFi异常。我 在设备的代码中,每次设备切换WiFi重启网络服务时,都调用res_init()接口,经过测试,解决了问题。

参考文章:https://blog.csdn.net/zhaowen_cug/article/details/81332760(如侵权请联系我删除)

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值