核心代码位于java.net.InetAddress.lookupHostByName(String host, int netId)
公共类InetAddress 实现可序列化{
.
/**
* 使用缓存将主机名解析为其IP 地址。
*
* @param host 要解析的主机名。
* @param netId 要执行解析的网络。
* @return 主机的IP地址。
*/
私有静态InetAddress[] LookupHostByName(String host, int netId)
抛出UnknownHostException {
BlockGuard.getThreadPolicy().onNetwork();
//我们有缓存结果吗?
对象cachedResult=addressCache.get(host, netId);
if (cachedResult !=null) {
if (cachedResult instanceof InetAddress[]) {
//缓存的肯定结果。
返回(InetAddress[]) 缓存结果;
} 别的{
//缓存的负结果。
抛出新的UnknownHostException((字符串)cachedResult);
}
}
尝试{
StructAddrinfo 提示=new StructAddrinfo();
提示.ai_flags=AI_ADDRCONFIG;
提示.ai_family=AF_UNSPEC;
//如果我们不指定套接字类型,每个地址都会出现两次,一次
//用于SOCK_STREAM,一个用于SOCK_DGRAM。既然我们不归还家人
//无论如何,只选一个。
提示.ai_socktype=SOCK_STREAM;
InetAddress[] 地址=Libcore.os.android_getaddrinfo(host,hints,netId);
//TODO: getaddrinfo 应该设置它返回的InetAddresses 的主机名吗?
for (InetAddress 地址: 个地址) {
地址.主机名=主机;
}
addressCache.put(主机、netId、地址);
返回地址;
} catch (GaiException gaiException) {
.
}
}
}其中addressCache是InetAddress的本地缓存:
私有静态最终地址缓存地址缓存=新地址缓存();结合InetAddress的解析策略,我们可以通过以下方法实现自定义DNS服务:
通过HttpDns SDK获取目标域名的IP,并使用反射获取InetAddress.addressCache对象。使用反射调用addressCache.put()方法。将域名和IP的对应关系写入InetAddress缓存中。具体实现可以参考如下代码:
公共类CustomDns {
公共静态无效writeSystemDnsCache(字符串主机名,字符串ip){
尝试{
类inetAddressClass=InetAddress.class;
字段字段=inetAddressClass.getDeclaredField("addressCache");
字段.setAccessible(true);
对象对象=field.get(inetAddressClass);
类cacheClass=object.getClass();
方法put 方法;
if(Build.VERSION.SDK_INT=Build.VERSION_CODES.LOLLIPOP) {
//api21及以上的put方法为put(String host, int netId, InetAddress[] address)
putMethod=cacheClass.getDeclaredMethod("put", String.class, int.class, InetAddress[].class);
} 别的{
//api20及以下的put方法为put(String host, InetAddress[] address)
putMethod=cacheClass.getDeclaredMethod("put", String.class, InetAddress[].class);
}
putMethod.setAccessible(true);
String[] ipStr=ip.split("\.");
byte[] ipBuf=新字节[4];
for(int i=0; i 4; i++) {
ipBuf[i]=(字节) (Integer.parseInt(ipStr[i])0xff);
}
if(Build.VERSION.SDK_INT=Build.VERSION_CODES.LOLLIPOP) {
putMethod.invoke(object, hostName, 0, new InetAddress[] {InetAddress.getByAddress(ipBuf)});
} 别的{
putMethod.invoke(object, hostName, new InetAddress[] {InetAddress.getByAddress(ipBuf)});
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}与一般方案相比,使用该方法有以下优点:
该方案实现简单,通用性强,适用于HTTPS、SNI、cookie设置等场景。避开证书验证、域名检查等环节,全球生效。 InetAddress.addressCache 是一个全局单例。该方案对所有使用InetAddress作为域名解析服务的请求生效。另外,使用该方案时请务必注意以下几点:
AddressCache默认TTL为2S,默认最多可保存16条缓存记录:
类地址缓存{
.
/**
* 当缓存包含的条目多于此时,我们开始删除最旧的条目。
* 这应该是2 的幂,以避免自定义地图中浪费空间。
*/
私有静态最终int MAX_ENTRIES=16;
//Java级缓存的TTL很短,只有2s。
私有静态最终长TTL_NANOS=2 * 1000000000L;
}
}Android虚拟机下的反射规则与JVM中不同,不能直接修改final变量的值。因此,使用该方法时请务必注意IP过期时间和缓存数量。另外,可以尝试另一种解决这个问题的方法:重写AddressCache类,先通过ClassLoader加载,覆盖系统类。
API 21 中更改了AddressCache.put 方法,并添加了netId 参数。为了保证兼容性,需要针对不同的版本进行不同的处理。具体解决方法可以参考上面的代码
文章分享结束,HttpClient与HttpURLConnection结合HttpDns的实践指南和的答案你都知道了吗?欢迎再次光临本站哦!
【HttpClient与HttpURLConnection结合HttpDns的实践指南】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
我一直在使用 HttpClient 和 HttpUrlConnection ,学习一下最佳实践希望能提高效率!
有11位网友表示赞同!
httpdns确实可以加速访问,这篇文章讲得怎么样?
有6位网友表示赞同!
要学起来HttpClient和HttpURLConnection啊,太久了!
有17位网友表示赞同!
做android开发的必备技能,好好看看这份最佳实践。
有6位网友表示赞同!
平时在项目中都是直接用这两个,没想过有这么多小技巧!
有12位网友表示赞同!
HttpDns能提高请求速度?这篇文章来帮帮忙啊!
有7位网友表示赞同!
想优化网络请求的流程?就看这份最佳实践了!
有19位网友表示赞同!
做web开发也有人用这些工具吧,还是看看区别。
有17位网友表示赞同!
学习新的知识总是一件好事,期待一篇干货满满的文章!
有13位网友表示赞同!
希望能学到一些新的调试技巧,这样处理网络请求就更方便了!
有11位网友表示赞同!
最近在学习Android开发,感觉HttpClient和HttpUrlConnection很有用,赶紧看看最佳实践!
有16位网友表示赞同!
希望文章能讲清楚一些使用场景,方便我根据实际项目来应用.
有14位网友表示赞同!
想了解一下HttpDns如何提高http请求效率?
有17位网友表示赞同!
有没有什么好的工具可以帮助我们测试HttpClient和HttpUrlConnection的性能?
有18位网友表示赞同!
这种最佳实践对不同网络环境有没有适用性差异?
有13位网友表示赞同!
好文章,分享一下给其他也在做Android开发的小伙伴!
有11位网友表示赞同!
希望能了解更多关于HttpClient 和 HttpUrlConnection 的详细介绍。
有15位网友表示赞同!
学习新的东西总能让我感觉更有动力!
有18位网友表示赞同!
赶紧把这篇文章收藏起来,以后有需要的直接就来翻阅一遍了!
有18位网友表示赞同!