问题:
如何清除手机中缓存的DNS信息,保证每次DNS解析都是直接走网络请求?
背景:
- 因为需求要求,需要对输入的IP地址或域名进行DNS解析,从而拿到其真实的DNS解析结果,这里想要知道DNS解析的实时结果。每次都想走网络请求,而非DNS缓存。
- 但是我们知道DNS只要解析一次,就会在手机中存在缓存了,第一层缓存是在APP进程中,第二层缓存是在本地native中。
解决思路:
- 上层缓存
- 对于APP进程中的缓存,应该是有办法进行清除。所以决定从看源码入手来查找对应方法。
- 首先看解析DNS用到的方法:
InetAddress.getAllByName()
3. 该方法入手,最终真正执行DNS逻辑的是类Inet6AddressImpl的方法 lookupHostByName。
- 入手该方法,会看到方法内使用到了一个集合,该集合缓存了DNS解析结果。
- 该集合是静态的,我们可以看到对于该集合,Inet6AddressImpl有提供对外方法进行清除缓存。
- 我们回到InetAddress,可以看到这里也有对外API暴露了清除缓存的方法。但是该方法被打上了hide标签,我们没法直接使用。
- 那这个时候可以使用反射来调用该方法了。通过反射调用该方法达到我们的目的。
-
native层缓存
上层缓存有方法解决,但是native层也存在缓存,如何解决呢?
对C代码不熟悉,分析源码不是很顺畅。
搜索了好久,也没有明确方法,包括询问了chatGpt,也没有明确答案。
- 思考场景
既然搜不到,那就看看有没有实际场景会用到这个。一般涉及到DNS解析的,都和网络请求关系紧密。那么VPN和DNS关系更密切。意识到,切换VPN是不是会清除缓存,直接走网络请求呢?
通过代码集成VPNService,打开VPN前后,分别做了一次DNS解析,使用wireshark分析发现每次都有发包。确定打开VPN会清除底层缓存,且上层缓存也会清除,直接一劳永逸。
于是乎,最终解决方案:
每次需要实际进行DNS解析时候,先通过VPNService开关一下VPN,然后再进行DNS解析获取结果。