Java网络编程从入门到精通(4):DNS缓存

简介:
在通过 DNS 查找域名的过程中,可能会经过多台中间 DNS 服务器才能找到指定的域名,因此,在 DNS 服务器上查找域名是非常昂贵的操作。在 Java 中为了缓解这个问题,提供了 DNS 缓存。当 InetAddress 类第一次使用某个域名(如 www.csdn.net )创建 InetAddress 对象后, JVM 就会将这个域名和它从 DNS 上获得的信息(如 IP 地址)都保存在 DNS 缓存中。当下一次 InetAddress 类再使用这个域名时,就直接从 DNS 缓存里获得所需的信息,而无需再访问 DNS 服务器。
DNS 缓存在默认时将永远保留曾经访问过的域名信息,但我们可以修改这个默认值。一般有两种方法可以修改这个默认值:
1.  在程序中通过java.security.Security.setProperty 方法设置安全属性networkaddress.cache.ttl 的值(单位:秒)。如下面的代码将缓存超时设为10 秒:
java.security.Security.setProperty( " networkaddress.cache.ttl " 10 );
2.  设置java.security 文件中的networkaddress.cache.negative.ttl 属性。假设JDK 的安装目录是C:\jdk1.6 ,那么java.security 文件位于c:\jdk1.6\jre\lib\security 目录中。打开这个文件,找到networkaddress.cache.ttl 属性,并将这个属性值设为相应的缓存超时(单位:秒)。
    如果将networkaddress.cache.ttl 属性值设为-1 ,那么DNS 缓存数据将永远不会释放。下面的代码 演示了使用和不使用DNS 缓存所产生效果:
package  mynet;

import  java.net. * ;

public   class  MyDNS
{
    
public   static   void  main(String[] args)  throws  Exception
    {
        
//  args[0]: 本机名 args[1]:缓冲时间
         if  (args.length  <   2 )
            
return ;
        java.security.Security.setProperty(
" networkaddress.cache.ttl " , args[ 1 ]);
        
long  time  =  System.currentTimeMillis();
        InetAddress addresses1[] 
=  InetAddress.getAllByName(args[ 0 ]);
        System.out.println(
" addresses1:    "
                        
+  String.valueOf(System.currentTimeMillis()  -  time)
                        
+   " 毫秒 " );
        
for  (InetAddress address : addresses1)
            System.out.println(address);
        System.out.print(
" 按任意键继续 " );
        System.in.read();
        time 
=  System.currentTimeMillis();
        InetAddress addresses2[] 
=  InetAddress.getAllByName(args[ 0 ]);
        System.out.println(
" addresses2:    "
                        
+  String.valueOf(System.currentTimeMillis()  -  time)
                        
+   " 毫秒 " );
        
for  (InetAddress address : addresses2)
            System.out.println(address);
    }
}
    在上面的代码中 设置了DNS 缓存超时(通过args[1]参数) ,用户可以通过命令行参数将这个值传入MyDNS 中。这个程序首先使用getAllByName 建立一个InetAddress 数组,然后通过System.in.read 使程序暂停。当用户等待一段时间后,可以按任意键继续,并使用同一个域名(args[0]) 再建立一个InetAddress 数组。如果用户等待的这段时间比DNS 缓存超时小,那么无论情况如何变化,addresses2 addresses1 数组中的元素是一样的,并且创建addresses2 数组所花费的时间一般为0 毫秒(小于1 毫秒后,Java 无法获得更精确的时间)。
   测试 1
执行如下命令(将DNS 缓存超时设为5 秒):
java mynet.MyDNS www. 126 .com  5
运行结果1 (在5 秒之内按任意键): 
addresses1:   344毫秒
www
.126 .com/ 202.108.9.77
按任意键继续
addresses2:  0毫秒
www
.126 .com/ 202.108.9.77
运行结果2 (在5 秒后按任意键): 
addresses1:   344毫秒
www
.126 .com/ 202.108.9.77
按任意键继续
addresses2:  484毫秒
www
.126 .com/ 202.108.9.77
在上面的测试中可能出现两个运行结果。如果在出现按任意键继续…” 后,在5 秒之内按任意键继续后,就会得到运行结果1 ,从这个结果可以看出,addresses2 所用的时间为0 毫秒,也就是说,addresses2 并未真正访问DNS 服务器,而是直接从内存中的DNS 缓存得到的数据。当在5 秒后按任意键继续后,就会得到运行结果2 ,这时,内存中的DNS 缓存中的数据已经释放,所以addresses2 还得再访问DNS 服务器,因此,addresses2 的时间是484 毫秒(addresses1 addresses2 后面的毫秒数可能在不同的环境下的值不一样,但一般情况下,运行结果1 addresses2 的值为0 或是一个接近0 的数,如5 。运行结果2 addresses2 的值一般会和addresses1 的值很接近,或是一个远比0 大的数,如1200 )。
测试 2
执行如下命令(ComputerName 为本机的计算机名,DNS 缓存超时设为永不过期[-1] ):
java mynet.MyDNS ComputerName - 1
运行结果(按任意键继续之前,将192.168.18.20 删除):
addresses1:   31毫秒
myuniverse/
192.168.18.10
myuniverse/
192.168.18.20
按任意键继续
addresses2:   0毫秒
myuniverse/
192.168.18.10
myuniverse/
192.168.18.20
     从上面的测试可以看出,将DNS 缓存设为永不过期后,无论过多少时间,按任意键后,addresses2 任然得到了两个IP 地址(192.168.18.10 192.168.18.20 ),而且addresses2 的时间是0 毫秒,但在这时192.168.18.20 已经被删除。因此可以判断,addresses2 是从DNS 缓存中得到的数据。如果运行如下的命令,并在5 秒后按任意键继续后,addresses2 就会只剩下一个IP 地址(192.168.18.10 )。 
java mynet.MyDNS ComputerName  5
如果域名在DNS 服务器上不存在,那么客户端在进行一段时间的尝试后(平均为5 秒),就会抛出一个UnknownHostException 异常。为了让下一次访问这个域名时不再等待,DNS 缓存将这个错误信息也保存了起来。也就是说,只有第一次访问错误域名时才进行5 称左右的尝试,以后再访问这个域名时将直接抛出UnknownHostException 异常,而无需再等待5 秒钟,
访问域名失败的原因可能是这个域名真的不存在,也可能是因为DNS 服务器或是其他的硬件或软件的临时故障,因此,一般不能将这个域名错误信息一直保留。在Java 中可以通过networkaddress.cache.negative.ttl 属性设置保留这些信息的时间。这个属性的默认值是10 秒。它也可以通过java.security.Security.setProperty 方法或java.security 文件来设置。下面的代码 演示了networkaddress.cache.negative.ttl 属性的用法:
package  mynet;

import  java.net. * ;

public   class  MyDNS1
{
    
public   static   void  main(String[] args)  throws  Exception
    {
        java.security.Security.setProperty(
" networkaddress.cache.negative.ttl " ,
                        
" 5 " );
        
long  time  =   0 ;
        
try
        {
            time 
=  System.currentTimeMillis();
            InetAddress.getByName(
" www.ppp123.com " );
        }
        
catch  (Exception e)
        {
            System.out.println(
" www.ppp123.com不存在! address1:  "
                            
+  String.valueOf(System.currentTimeMillis()  -  time)
                            
+   " 毫秒 " );
        }
        
// Thread.sleep(6000);  //  延迟6秒
         try
        {
            time 
=  System.currentTimeMillis();
            InetAddress.getByName(
" www.ppp123.com " );
        }
        
catch  (Exception e)
        {
            System.out.println(
" www.ppp123.com不存在! address2:  "
                            
+  String.valueOf(System.currentTimeMillis()  -  time)
                            
+   " 毫秒 " );
        }
    }
}
在上面的代码中 networkaddress.cache.negative.ttl 属性值设为5 秒。这个程序分别测试了address1 address2 访问www.ppp123.com (这是个不存在的域名,读者可以将其换成任何不存在的域名)后,用了多长时间抛出UnknownHostException 异常。
运行结果:
www.ppp123.com不存在! address1:  4688毫秒
www.ppp123.com不存在! address2:  0毫秒
    我们从上面的运行结果可以看出,address2 使用了0 毫秒就抛出了异常,因此,可以断定address2 是从DNS 缓存里获得了域名www.ppp123.com 不可访问的信息,所以就直接抛出了UnknowHostException 异常。如果将上面代码中的延迟代码 的注释去掉, 那么可能得到如下的运行结果:
www.ppp123.com不存在! address1:  4688毫秒
www.ppp123.com不存在! address1:  4420毫秒
从上面的运行结果可以看出,在第6 秒时,DNS 缓存中的数据已经被释放,因此,address2 仍需要访问DNS 服务器才能知道www.ppp123.com 是不可访问的域名。 
在使用DNS缓存时有两点需要注意:
1.  可以根据实际情况来设置networkaddress.cache.ttl 属性的值。一般将这个属性的值设为-1 。但如果访问的是动态映射的域名(如使用动态域名服务将域名映射成ADSL 的动态IP 就可能产生IP 地址变化后,客户端得到的还是原来的IP 地址的情况。
2.  在设置networkaddress.cache.negative.ttl 属性值时最好不要将它设为-1 否则如果一个域名因为暂时的故障而无法访问,那么程序再次访问这个域名时,即使这个域名恢复正常,程序也无法再访问这个域名了。除非重新运行程序。



 本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/214814,如需转载请自行联系原作者

相关文章
|
监控 安全 网络安全
深入解析PDCERF:网络安全应急响应的六阶段方法
PDCERF是网络安全应急响应的六阶段方法,涵盖准备、检测、抑制、根除、恢复和跟进。本文详细解析各阶段目标与操作步骤,并附图例,助读者理解与应用,提升组织应对安全事件的能力。
2016 89
|
10月前
|
网络协议 安全 Devops
Infoblox DDI (NIOS) 9.0 - DNS、DHCP 和 IPAM (DDI) 核心网络服务管理
Infoblox DDI (NIOS) 9.0 - DNS、DHCP 和 IPAM (DDI) 核心网络服务管理
395 4
|
机器学习/深度学习 数据可视化 PyTorch
深入解析图神经网络注意力机制:数学原理与可视化实现
本文深入解析了图神经网络(GNNs)中自注意力机制的内部运作原理,通过可视化和数学推导揭示其工作机制。文章采用“位置-转移图”概念框架,并使用NumPy实现代码示例,逐步拆解自注意力层的计算过程。文中详细展示了从节点特征矩阵、邻接矩阵到生成注意力权重的具体步骤,并通过四个类(GAL1至GAL4)模拟了整个计算流程。最终,结合实际PyTorch Geometric库中的代码,对比分析了核心逻辑,为理解GNN自注意力机制提供了清晰的学习路径。
769 7
深入解析图神经网络注意力机制:数学原理与可视化实现
|
12月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
449 15
|
12月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
缓存 边缘计算 安全
阿里云CDN:全球加速网络的实践创新与价值解析
在数字化浪潮下,用户体验成为企业竞争力的核心。阿里云CDN凭借技术创新与全球化布局,提供高效稳定的加速解决方案。其三层优化体系(智能调度、缓存策略、安全防护)确保低延迟和高命中率,覆盖2800+全球节点,支持电商、教育、游戏等行业,帮助企业节省带宽成本,提升加载速度和安全性。未来,阿里云CDN将继续引领内容分发的行业标准。
653 7
|
云安全 人工智能 安全
阿里云网络安全体系解析:如何构建数字时代的"安全盾牌"
在数字经济时代,阿里云作为亚太地区最大的云服务提供商,构建了行业领先的网络安全体系。本文解析其网络安全架构的三大核心维度:基础架构安全、核心技术防护和安全管理体系。通过技术创新与体系化防御,阿里云为企业数字化转型提供坚实的安全屏障,确保数据安全与业务连续性。案例显示,某金融客户借助阿里云成功拦截3200万次攻击,降低运维成本40%,响应时间缩短至8分钟。未来,阿里云将继续推进自适应安全架构,助力企业提升核心竞争力。
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
689 11
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
1894 30
|
网络协议
TCP报文格式全解析:网络小白变高手的必读指南
本文深入解析TCP报文格式,涵盖源端口、目的端口、序号、确认序号、首部长度、标志字段、窗口大小、检验和、紧急指针及选项字段。每个字段的作用和意义详尽说明,帮助理解TCP协议如何确保可靠的数据传输,是互联网通信的基石。通过学习这些内容,读者可以更好地掌握TCP的工作原理及其在网络中的应用。

相关产品

  • 云解析DNS
  • 推荐镜像

    更多
  • DNS