TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
在通过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.6jrelibsecurity
目录中。打开这个文件,找到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
,否则如果一个域名因为暂时的故障而无法访问,那么程序再次访问这个域名时,即使这个域名恢复正常,程序也无法再访问这个域名 了。除非重新运行程序。
本文出自 “软件改变整个宇宙” 博客,请务必保留此出处http://androidguy.blog.51cto.com/974126/214814
源码下载:http://file.javaxxz.com/2014/11/7/000437890.zip |
|