熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

Java網絡編程從入門到精通(4):DNS緩存

2013-11-12 23:37:23  來源: Java核心技術 

  在通過DNS查找域名的過程中可能會經過多台中間DNS服務器才能找到指定的域名因此在DNS服務器上查找域名是非常昂貴的操作在Java中為了緩解這個問題提供了DNS緩存當InetAddress類第一次使用某個域名(如)創建InetAddress對象後JVM就會將這個域名和它從DNS上獲得的信息(如IP地址)都保存在DNS緩存中當下一次InetAddress類再使用這個域名時就直接從DNS緩存裡獲得所需的信息而無需再訪問DNS服務器

  DNS緩存在默認時將永遠保留曾經訪問過的域名信息但我們可以修改這個默認值一般有兩種方法可以修改這個默認值

   在程序中通過javasecuritySecuritysetProperty方法設置安全屬性netwl的值(單位秒)如下面的代碼將緩存超時設為

   javasecuritySecuritysetProperty(netwl );

   設置javasecurity文件中的networkaddresl屬性假設JDK的安裝目錄是C\jdk那麼javasecurity文件位於c\jdk\jre\lib\security目錄中打開這個文件找到netwl屬性並將這個屬性值設為相應的緩存超時(單位秒)

  如果將netwl屬性值設為那麼DNS緩存數據將永遠不會釋放下面的代碼演示了使用和不使用DNS緩存所產生效果

   package mynet;

import *;

public class MyDNS
{
    public static void main(String[] args) throws Exception
    {
        // args[]: 本機名 args[]緩沖時間
        if (argslength < )
            return;
        javasecuritySecuritysetProperty(netwl args[]);
        long time = SystemcurrentTimeMillis();
        InetAddress addresses[] = InetAddressgetAllByName(args[]);
        Systemoutprintln(addresses:   
                        + StringvalueOf(SystemcurrentTimeMillis()  time)
                        + 毫秒);
        for (InetAddress address : addresses)
            Systemoutprintln(address);
        Systemoutprint(按任意鍵繼續);
        Systeminread();
        time = SystemcurrentTimeMillis();
        InetAddress addresses[] = InetAddressgetAllByName(args[]);
        Systemoutprintln(addresses:   
                        + StringvalueOf(SystemcurrentTimeMillis()  time)
                        + 毫秒);
        for (InetAddress address : addresses)
            Systemoutprintln(address);
    }
}

  在上面的代碼中設置了DNS緩存超時(通過args[]參數)用戶可以通過命令行參數將這個值傳入MyDNS中這個程序首先使用getAllByName建立一個InetAddress數組然後通過Systeminread使程序暫停當用戶等待一段時間後可以按任意鍵繼續並使用同一個域名(args[])再建立一個InetAddress數組如果用戶等待的這段時間比DNS緩存超時小那麼無論情況如何變化addresses和addresses數組中的元素是一樣的並且創建addresses數組所花費的時間一般為毫秒(小於毫秒後Java無法獲得更精確的時間)

  測試

  執行如下命令(將DNS緩存超時設為秒)

   java mynetMyDNS  

  運行結果(在秒之內按任意鍵)

   addresses:   毫秒
/
按任意鍵繼續
addresses:  毫秒
/

  運行結果(在秒後按任意鍵)

   addresses:   毫秒
/
按任意鍵繼續
addresses:  毫秒
/

  在上面的測試中可能出現兩個運行結果如果在出現按任意鍵繼續…秒之內按任意鍵繼續後就會得到運行結果從這個結果可以看出addresses所用的時間為毫秒也就是說addresses並未真正訪問DNS服務器而是直接從內存中的DNS緩存得到的數據當在秒後按任意鍵繼續後就會得到運行結果這時內存中的DNS緩存中的數據已經釋放所以addresses還得再訪問DNS服務器因此addresses的時間是毫秒(addresses和addresses後面的毫秒數可能在不同的環境下的值不一樣但一般情況下運行結果的addresses的值為或是一個接近的數運行結果的addresses的值一般會和addresses的值很接近或是一個遠比大的數

  測試

  執行如下命令(ComputerName為本機的計算機名DNS緩存超時設為永不過期[])

   java mynetMyDNS ComputerName 

  運行結果(按任意鍵繼續之前刪除)

   addresses:   毫秒
myuniverse/
myuniverse/
按任意鍵繼續
addresses:   毫秒
myuniverse/
myuniverse/

  從上面的測試可以看出將DNS緩存設為永不過期後無論過多少時間按任意鍵後addresses任然得到了兩個IP地址(而且addresses的時間是毫秒但在這時已經被刪除因此可以判斷addresses是從DNS緩存中得到的數據如果運行如下的命令並在秒後按任意鍵繼續後addresses就會只剩下一個IP地址(

   java mynetMyDNS ComputerName 

  如果域名在DNS服務器上不存在那麼客戶端在進行一段時間的嘗試後(平均為秒)就會拋出一個UnknownHostException異常為了讓下一次訪問這個域名時不再等待DNS緩存將這個錯誤信息也保存了起來也就是說只有第一次訪問錯誤域名時才進行稱左右的嘗試以後再訪問這個域名時將直接拋出UnknownHostException異常而無需再等待秒鐘

  訪問域名失敗的原因可能是這個域名真的不存在也可能是因為DNS服務器或是其他的硬件或軟件的臨時故障因此一般不能將這個域名錯誤信息一直保留在Java中可以通過networkaddresl屬性設置保留這些信息的時間這個屬性的默認值是它也可以通過javasecuritySecuritysetProperty方法或javasecurity文件來設置下面的代碼演示了networkaddresl屬性的用法

   package mynet;

import *;

public class MyDNS
{
    public static void main(String[] args) throws Exception
    {
        javasecuritySecuritysetProperty(networkaddresl
                        );
        long time = ;
        try
        {
            time = SystemcurrentTimeMillis();
            InetAddressgetByName();
        }
        catch (Exception e)
        {
            Systemoutprintln(不存在! address
                            + StringvalueOf(SystemcurrentTimeMillis()  time)
                            + 毫秒);
        }
        //Threadsleep(); // 延遲
        try
        {
            time = SystemcurrentTimeMillis();
            InetAddressgetByName();
        }
        catch (Exception e)
        {
            Systemoutprintln(不存在! address
                            + StringvalueOf(SystemcurrentTimeMillis()  time)
                            + 毫秒);
        }
    }
}

  在上面的代碼中將networkaddresl屬性值設為這個程序分別測試了address和address訪問(這是個不存在的域名讀者可以將其換成任何不存在的域名)後用了多長時間拋出UnknownHostException異常

  運行結果

   不存在! address:  毫秒
不存在! address:  毫秒

  我們從上面的運行結果可以看出address使用了毫秒就拋出了異常因此可以斷定address是從DNS緩存裡獲得了域名不可訪問的信息所以就直接拋出了UnknowHostException異常如果將上面代碼中的延遲代碼的注釋去掉那麼可能得到如下的運行結果

   不存在! address:  毫秒
不存在! address:  毫秒

  從上面的運行結果可以看出在第秒時DNS緩存中的數據已經被釋放因此address仍需要訪問DNS服務器才能知道是不可訪問的域名

  在使用DNS緩存時有兩點需要注意

   可以根據實際情況來設置netwl屬性的值一般將這個屬性的值設為但如果訪問的是動態映射的域名(如使用動態域名服務將域名映射成ADSL的動態IP) 就可能產生IP地址變化後客戶端得到的還是原來的IP地址的情況

   在設置networkaddresl屬性值時最好不要將它設為否則如果一個域名因為暫時的故障而無法訪問那麼程序再次訪問這個域名時即使這個域名恢復正常程序也無法再訪問這個域名了除非重新運行程序


From:http://tw.wingwit.com/Article/program/Java/hx/201311/11147.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.