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

简介: 本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:Java网络编程从入门到精通(3):为什么不能直接通过IP访问网站     在通过DNS查找域名的过程中,可能会经过多台中间DNS服务器才能找到指定的域名,因此,在DNS服务器上查找域名是非常昂贵的操作。

本文为原创,如需转载,请注明作者和出处,谢谢!

上一篇:Java网络编程从入门到精通(3):为什么不能直接通过IP访问网站

    在通过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缓存超时小,那么无论情况如何变化,addresses2addresses1数组中的元素是一样的,并且创建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毫秒(addresses1addresses2后面的毫秒数可能在不同的环境下的值不一样,但一般情况下,运行结果1addresses2的值为0或是一个接近0的数,如5。运行结果2addresses2的值一般会和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.10192.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秒。这个程序分别测试了address1address2访问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否则如果一个域名因为暂时的故障而无法访问,那么程序再次访问这个域名时,即使这个域名恢复正常,程序也无法再访问这个域名了。除非重新运行程序。

下一篇:Java网络编程从入门到精通(5):使用InetAddress类的getHostName方法获得域名



国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

目录
相关文章
|
4月前
|
网络协议 安全 Devops
Infoblox DDI (NIOS) 9.0 - DNS、DHCP 和 IPAM (DDI) 核心网络服务管理
Infoblox DDI (NIOS) 9.0 - DNS、DHCP 和 IPAM (DDI) 核心网络服务管理
123 4
|
8月前
|
监控 安全 网络安全
深入解析PDCERF:网络安全应急响应的六阶段方法
PDCERF是网络安全应急响应的六阶段方法,涵盖准备、检测、抑制、根除、恢复和跟进。本文详细解析各阶段目标与操作步骤,并附图例,助读者理解与应用,提升组织应对安全事件的能力。
1064 89
|
6月前
|
机器学习/深度学习 数据可视化 PyTorch
深入解析图神经网络注意力机制:数学原理与可视化实现
本文深入解析了图神经网络(GNNs)中自注意力机制的内部运作原理,通过可视化和数学推导揭示其工作机制。文章采用“位置-转移图”概念框架,并使用NumPy实现代码示例,逐步拆解自注意力层的计算过程。文中详细展示了从节点特征矩阵、邻接矩阵到生成注意力权重的具体步骤,并通过四个类(GAL1至GAL4)模拟了整个计算流程。最终,结合实际PyTorch Geometric库中的代码,对比分析了核心逻辑,为理解GNN自注意力机制提供了清晰的学习路径。
454 7
深入解析图神经网络注意力机制:数学原理与可视化实现
|
6月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
161 15
|
6月前
|
Web App开发 移动开发 前端开发
React音频播放器样式自定义全解析:从入门到避坑指南
在React中使用HTML5原生&lt;audio&gt;标签时,开发者常面临视觉一致性缺失、样式定制局限和交互体验割裂等问题。通过隐藏原生控件并构建自定义UI层,可以实现完全可控的播放器视觉风格,避免状态不同步等典型问题。结合事件监听、进度条拖拽、浏览器兼容性处理及性能优化技巧,可构建高性能、可维护的音频组件,满足跨平台需求。建议优先使用成熟音频库(如react-player),仅在深度定制需求时采用原生方案。
212 12
|
7月前
|
存储 索引 Python
Python入门:6.深入解析Python中的序列
在 Python 中,**序列**是一种有序的数据结构,广泛应用于数据存储、操作和处理。序列的一个显著特点是支持通过**索引**访问数据。常见的序列类型包括字符串(`str`)、列表(`list`)和元组(`tuple`)。这些序列各有特点,既可以存储简单的字符,也可以存储复杂的对象。 为了帮助初学者掌握 Python 中的序列操作,本文将围绕**字符串**、**列表**和**元组**这三种序列类型,详细介绍其定义、常用方法和具体示例。
Python入门:6.深入解析Python中的序列
|
6月前
|
Java 关系型数据库 数据库连接
Javaweb之Mybatis入门程序的详细解析
本文详细介绍了一个MyBatis入门程序的创建过程,从环境准备、Maven项目创建、MyBatis配置、实体类和Mapper接口的定义,到工具类和测试类的编写。通过这个示例,读者可以了解MyBatis的基本使用方法,并在实际项目中应用这些知识。
142 11
|
7月前
|
存储 Linux iOS开发
Python入门:2.注释与变量的全面解析
在学习Python编程的过程中,注释和变量是必须掌握的两个基础概念。注释帮助我们理解代码的意图,而变量则是用于存储和操作数据的核心工具。熟练掌握这两者,不仅能提高代码的可读性和维护性,还能为后续学习复杂编程概念打下坚实的基础。
Python入门:2.注释与变量的全面解析
|
6月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
6月前
|
缓存 边缘计算 安全
阿里云CDN:全球加速网络的实践创新与价值解析
在数字化浪潮下,用户体验成为企业竞争力的核心。阿里云CDN凭借技术创新与全球化布局,提供高效稳定的加速解决方案。其三层优化体系(智能调度、缓存策略、安全防护)确保低延迟和高命中率,覆盖2800+全球节点,支持电商、教育、游戏等行业,帮助企业节省带宽成本,提升加载速度和安全性。未来,阿里云CDN将继续引领内容分发的行业标准。
381 7

相关产品

  • 云解析DNS
  • 推荐镜像

    更多
  • DNS