Java使用域名查詢時,用的本身內部的域名實現機制,最後都是交給InetAddress去作DNS解析。html
源碼分析參考:http://blog.arganzheng.me/posts/java-dns-lookup-internal.htmljava
//域名查詢 String dottedQuadIpAddress = InetAddress.getByName( "blog.arganzheng.me" ).getHostAddress(); //IP對應域名 InetAddress[] addresses = InetAddress.getAllByName("8.8.8.8"); // ip or DNS name for (int i = 0; i < addresses.length; i++) { String hostname = addresses[i].getHostName(); System.out.println(hostname); }
http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.htmllinux
sun.net.spi.nameservice.provider.<n>=<default|dns,sun|...>Specifies the name service provider that you can use. By default, Java will use the system configured name lookup mechanism, such as file, nis, etc. You can specify your own by setting this option. <n> takes the value of a positive number, it indicates the precedence order with a small number takes higher precendence over a bigger number. Aside from the default provider, the JDK includes a DNS provider named "dns,sun".nginx
Prior to JDK 7, the first provider that was successfully loaded was used. In JDK 7, providers are chained, which means that if a lookup on a provider fails, the next provider in the list is consulted to resolve the name.緩存
重點是這個參數,區分jdk版本,jdk7以前,只有第一個設置的provier生效;jdk7及其以後,provider鏈都生效,從第一個開始,指導解析成功。服務器
Java有兩個實現:oracle
Default:至關於設置System.setProperty("sun.net.spi.nameservice.provider.1", "default"); 具體解析過程是系統調用(getaddrinfo),依賴系統的DNS解析方式。app
getaddrinfo:https://linux.die.net/man/3/getaddrinfodom
Linux 系統如何處理名稱解析: https://blog.arstercz.com/linux-%E7%B3%BB%E7%BB%9F%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%90%8D%E7%A7%B0%E8%A7%A3%E6%9E%90/ide
getaddrinfo工做原理分析: http://www.javashuo.com/article/p-xwkmdawc-hz.html
resolv.conf文件更新了,getaddrinfo系統調用感知不到,它只會加載一次: https://stackoverflow.com/questions/19930037/an-issue-of-getaddrinfo-function-call-on-linux-platform
linux 默認的DNS方式是讀取/etc/resolv.conf進行DNS解析。
resolv.conf文件變動了,java進程感知不到,必須得程序重啓才能生效
Linux 系統如何處理名稱解析: https://blog.arstercz.com/linux-%E7%B3%BB%E7%BB%9F%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%90%8D%E7%A7%B0%E8%A7%A3%E6%9E%90/
修改 resolv.conf 裏的 dns server, 多數運行的程序不會當即生效. Centos 7 系統中, glibc-2.17-202 版本合併了官方 glibc-2.25.90-18 的功能, 增長了自動檢測 resolv.conf 修改功能, 以下:
# rpm -q --changelog glibc-2.17-260
...
* Fri Sep 29 2017 Florian Weimer <fweimer@redhat.com> - 2.17-202
....
- Detect and apply /etc/resolv.conf changes in libresolv (#1432085)
mac 默認的方式是向網關請求獲取DNS服務器,而後直接請求DNS服務器進行解析,沒有讀取/etc/resolv.conf。
<dns,sun>:System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun"); 讀取/etc/resolv.conf進行DNS解析,不一樣於默認的用getaddrinfo系統調用。
不一樣於「default」, 使用"dns,sun",每5分鐘會讀取一次/etc/resolv.conf,更新內存中的dns nameserver。
sun.net.spi.nameservice.nameservers=<server1_ipaddr,server2_ipaddr ...>You can specify a comma separated list of IP addresses that point to the DNS servers you want to use. If the sun.net.spi.nameservice.nameservers property is not defined, then the provider will use any name servers already configured in the platform DNS configuration.
sun.net.spi.nameservice.domain=<domainname>This property specifies the default DNS domain name, for instance, eng.example.com. If the sun.net.spi.nameservice.domain property is not defined then the provider will use any domain or domain search list configured in the platform DNS configuration.
使用dnsjava的provider:
1. 工程添加dnsjava包。
2. 設置provider:System.setProperty("sun.net.spi.nameservice.provider.1","dns,dnsjava");
dnsjava的provider功能強大:
There's no standard way to determine what the local nameserver or DNS search
path is at runtime from within the JVM. dnsjava attempts several methods
until one succeeds.
- The properties 'dns.server' and 'dns.search' (comma delimited lists) are
checked. The servers can either be IP addresses or hostnames (which are
resolved using Java's built in DNS support).
- The sun.net.dns.ResolverConfiguration class is queried.
- On Unix, /etc/resolv.conf is parsed.
- On Windows, ipconfig/winipcfg is called and its output parsed. This may
fail for non-English versions on Windows.
- As a last resort, "localhost" is used as the nameserver, and the search
path is empty.
參考:
http://www.xbill.org/dnsjava/dnsjava-current/README
http://stackoverflow.com/questions/5668058/how-to-change-the-java-dns-service-provider
若是啓動了security manager,則永久緩存,但通常狀況下你們是不會去啓動security manager的。
能夠再程序裏面設置不緩存,或者在啓動參數裏面設置
java.security.Security.setProperty("networkaddress.cache.ttl" , "0")
若是沒有啓動security manager,則要區分JDK版本:
1.5及其一下,java對DNS解析IP進行緩存,默認緩存超時時間爲-1(在重啓JVM前永久緩存)
1.6及其以上,緩存時間根據ttl。
參考:
http://docs.oracle.com/javase/1.5.0/docs/guide/net/properties.html
http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html
設置ttl:在命令啓動JVM的時候設置參數"-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"
linux自己是沒有dns緩存的,想使用dns緩存的話須要本身安裝一個服務程序NSCD.
$ ps aux | grep nscd 能夠查看
相關問題:http://blogread.cn/it/article/7043?f=wb
主機A,B(可再也不同一網段),主機B有域名假設爲www.baidu.com
首先:1. 本地主機A在命令行下執行"ipconfig/flushdns"命令來清空本地DNS高速緩存;
2. 本地主機A在命令行下執行"arp -d"命令來清空arp緩存
而後,主機A執行ping www.baidu.com(即主機B的域名)
在此過程當中都發生了那些報文交互?
思路:
1.要執行ping命令主機A必須將域名轉化爲IP地址,故而必定會有DNS解析過程;
2.在DNS解析以前,主機A必定要知道本身默認網關的MAC地址,這就要涉及到ARP解析的問題;
3.ping命令自己是ICMP回顯請求,故而確定要有ICMP協議的回顯請求交互。
如下是全過程:
(此處可參照「跨網段的ping過程」來看,此處假設DNS服務器和主機A不在同一網段,若兩者在同一網段那麼我想只需進行簡單arp就可獲得DNS服務器的mac不需通過網關)
1.主機A發送ARP請求報文目的mac爲FFFFFF-FFFFFF,目的IP爲網關的IP,要求得到網關的MAC地址;
2.路由器(主機A的默認網關)發送目的mac爲A的mac,目的IP爲A的IP的ARP回答報文,以告知A網關的mac地址;
3.A得到網關的mac地址後,就向網關發送一個DNS查詢報文,其目的mac地址爲網關的mac地址,目的IP爲DNS服務器的IP地址;
4.網關收到DNS查詢報文後,拆包檢查發現是DNS查詢因而將相應(查詢)信息封裝,向DNS服務器發送該報文,其目的IP地址爲DNS服務器的IP,目的mac爲下一跳的mac,解析域名IP地址此時就交給了DNS服務器;
5.通過DNS解析,主機A知道了所要ping的域名的ip地址;
6.剩下的ping過程就和ping一個特定的ip地址相同了,首先判斷ping命令的目的B的IP地址是否和A在同一網段,若在同一網段則至關於同網段內ping,若不在同一網段,就是不一樣網段的ping只不過此時主機不須要再解析網關的mac地址了。
參考:
http://blog.sina.com.cn/s/blog_7c35df9b0100vomk.html