第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Java Socket 地址結(jié)構(gòu)

1. 前言

我們知道計算機(jī)網(wǎng)絡(luò)中連接的設(shè)備有很多,比如 PC、手機(jī)、打印機(jī)、路由器、交換機(jī)、網(wǎng)關(guān)等,通常把這些網(wǎng)絡(luò)設(shè)備叫做節(jié)點(Node)。每一個節(jié)點都分配有唯一的 IP 地址,用以標(biāo)識此設(shè)備。IP 地址包含 32 位 IPv4 和 128 位 IPv6 兩個版本。由于 IP 地址是一串?dāng)?shù)字或者是字節(jié)序列,對計算機(jī)是友好的,但是對我們?nèi)祟惙浅2挥押?,不利于傳播、記憶。為此,計算機(jī)科學(xué)家又開發(fā)了一套 DNS 系統(tǒng),給每一臺計算機(jī)分配了唯一的、對人類友好的主機(jī)名字,通常叫做域名。比如,idcbgp.cn 是慕課網(wǎng)主站的域名。當(dāng)然,有的主機(jī)會分配多個域名。

人們常說生活沒有那么簡單,往往是解決了一個老問題,又引出了新問題。當(dāng)你開發(fā)了 DNS 系統(tǒng)以后,我們?nèi)祟惔_實方便了,可是域名對計算機(jī)來說不方便,計算機(jī)更喜歡 IP 地址。這就又需要解決 IP 地址和域名之間相互解析、映射的問題,當(dāng)然這些問題在 DNS 系統(tǒng)中都得到了妥善的處理。域名解析系統(tǒng)是一個分布式集群系統(tǒng),是一個樹形結(jié)構(gòu)。一次域名解析可能需要經(jīng)過本地緩存、本地域名服務(wù)器、遠(yuǎn)程域名服務(wù)器之間多次交互。

從上面的描述可以看出,IP 地址和域名之間的相互解析是一套非常復(fù)雜的機(jī)制。好在操作系統(tǒng)將這一套復(fù)雜的機(jī)制進(jìn)行了封裝,以 API 的形式提供給網(wǎng)絡(luò)程序員,這樣極大的簡化了編程的復(fù)雜度。

一般操作系統(tǒng)都提供了 C 語言接口 getaddrinfogetnameinfo,前者的功能是通過域名獲取 IP 地址,后者的功能是通過 IP 地址獲取域名。

在 Java 平臺中,java.net.InetAddress 類實現(xiàn)了完整的 IP 地址和域名之間的相互解析機(jī)制。

2. InetAddress 類的體系結(jié)構(gòu)

java.net.InetAddress 類的體系結(jié)構(gòu)如下:

圖片描述

各類的功能說明:

  • InetAddress 是 Java IP 地址的包裝類,也是域名解析的核心類。
  • Inet4Address 代表了 IPv4 地址格式的封裝,一般程序員不需要關(guān)心此類。
  • Inet6Address 代表了 IPv6 地址格式的封裝,一般程序員不需要關(guān)心此類。
  • InetSocketAddress 是 Socket 地址的封裝,它通過私有內(nèi)部類 InetSocketAddressHolder 間接包裝了 InetAddress 結(jié)構(gòu)和 端口號(Port)。在網(wǎng)絡(luò)編程中,通常把 Socket 地址叫做 Endpoint,用 <IP, Port> 的組合來表示。

在網(wǎng)絡(luò)編程中,應(yīng)用最為頻繁的兩個類是 InetSocketAddress 和 InetAddress。其中,InetSocketAddress 類對 InetAddress 和 Port 進(jìn)行了封裝,形成了完整的 Socket 地址。而 InetAddress 核心實現(xiàn)就是域名解析和緩存。

InetAddress 類沒有 public 構(gòu)造方法,提供了一組 public static 工廠方法用以創(chuàng)建 InetAddress 實例。接下來,我們重點分析一下 getByName 和 getByAddress 兩類方法。

3. getByName 方法

InetAddress 提供了兩個公有靜態(tài)方法 getByName 和 getAllByName 來構(gòu)造 InetAddress 實例,它們的原型如下:

// 創(chuàng)建單個 InetAddress 實例
public static InetAddress getByName(String host) throws UnknownHostException
// 創(chuàng)建多個 InetAddress 實例
public static InetAddress[] getAllByName(String host) throws UnknownHostException

這兩個方法都會連接域名解析服務(wù)器進(jìn)行域名解析,具體工作原理如下:

  • 首先會檢查傳入?yún)?shù) host,也就是域名。如果傳入?yún)?shù)為 null,那么會返回以 loopback 地址構(gòu)造的 InetAddress 結(jié)構(gòu)。
  • 如果輸入?yún)?shù) host 是一個 IP 地址,那么根據(jù) IP 地址是 IPv4 還是 IPv6,分別構(gòu)造 Inet4Address 或 Inet6Address 結(jié)構(gòu),并且返回。
  • 查詢本地 Cache,如果本地 Cache 中已經(jīng)存在 host 相應(yīng)的地址,則直接返回。
  • 如果本地 Cache 查詢失敗,則遍歷本地注冊的 name services。如果有定制的 name services 注冊,那么會調(diào)用此定制的 name services。如果沒有定制的 name services,那么會調(diào)用 default name services,最終會調(diào)用系統(tǒng)的 getaddrinfo 函數(shù)。getaddrinfo 是一個 POSIX 標(biāo)準(zhǔn)函數(shù),一般系統(tǒng)都會實現(xiàn)。

getByName 方法的應(yīng)用非常簡單,示例如下:

public static void testInetAddressByName(String host){
        try {
            InetAddress addr = InetAddress.getByName(host);
            System.out.println("getByName addr=" + addr.toString());

            InetAddress[] addrs = InetAddress.getAllByName(host);
            for (InetAddress a: addrs){
                System.out.println("getAllByName addr=" + a.toString());
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

測試 widcbgp.cn 域名,執(zhí)行結(jié)果如下:

getByName addr=idcbgp.cn/115.182.41.103
getAllByName addr=idcbgp.cn/115.182.41.103
getAllByName addr=idcbgp.cn/117.121.101.144
getAllByName addr=idcbgp.cn/115.182.41.180
getAllByName addr=idcbgp.cn/117.121.101.40
getAllByName addr=idcbgp.cn/117.121.101.134
getAllByName addr=idcbgp.cn/115.182.41.163

需要注意的是 getByName 方法會拋出 UnknownHostException 異常,需要捕獲。

4. getByAddress 方法

如果你有明確的 IP 地址,并不需要進(jìn)行域名解析,可以調(diào)用 InetAddress 提供的另一組工廠方法 getByAddress,方法原型如下:

public static InetAddress getByAddress(byte[] addr) throws UnknownHostException

public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException

這是兩個重載的 public static 方法,功能都類似:

  • 第一個重載的 getByAddress 方法提供一個參數(shù),即用 byte [] 類型的數(shù)組表示的 IP 地址。
  • 第二個重載的 getByAddress 方法提供兩個參數(shù),用 String 類型表示的域名(host),和用 byte [] 類型的數(shù)組表示的 IP 地址。
  • 二者都不進(jìn)行域名解析,只是根據(jù)輸入?yún)?shù)構(gòu)造 InetAddress 實例。
  • 接收 host 輸入?yún)?shù)的 getByAddress 方法不保證域名和 IP 地址的對應(yīng)關(guān)系,也不保證域名是否可以訪問。

getByAddress 方法應(yīng)用的示例代碼如下:

public static void testInetAddressByAddr()
    {
        byte[] ips = new byte[]{ (byte)192, (byte)168,1,101};
        try {
            InetAddress addr = InetAddress.getByAddress(ips);
            System.out.println("getByAddress addr=" + addr.toString());

            InetAddress addr2 = InetAddress.getByAddress("www.example.com", ips);
            System.out.println("getByAddress with host addr=" + addr2.toString());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

我們輸入 192.168.1.101,執(zhí)行結(jié)果如下:

getByAddress addr=/192.168.1.101
getByAddress with host addr=www.example.com/192.168.1.101

5. InetAddress 的 Cache 策略

由于域名解析需要客戶端和域名服務(wù)器經(jīng)過很多次交互,一般都比較耗費時間,所以 InetAddress 提供了 Cache 機(jī)制。這樣,當(dāng)客戶程序調(diào)用 getByName 解析域名的時候,首先是從 Cache 中查找,這樣可以極大提高域名解析的效率。

域名綁定的 IP 地址可能會發(fā)生變化,所以 Cache 中存儲的 IP 地址也是有生命周期的。Java 提供了兩個全局參數(shù)可以用來配置 Cache 的有效時間。

  • networkaddress.cache.ttl
    成功解析的域名在 Cache 中的存活時間。

  • networkaddress.cache.negative.ttl
    解析失敗的域名在 Cache 中的存活時間。

實際上除了 Java 本地有 Cache 機(jī)制,域名解析服務(wù)器也是有 Cache 機(jī)制的,目的都是相同的。

6. 小結(jié)

InetAddress 類在網(wǎng)絡(luò)編程中的應(yīng)用是非常頻繁的,了解域名解析機(jī)制有利于我們更好的應(yīng)用此類的功能。在實際產(chǎn)品應(yīng)用中都是通過 getByName 方法構(gòu)造 InetAddress 實例的,盡量避免通過 getByAddress 方法構(gòu)造 InetAddress 實例。這樣可以提高程序的維護(hù)性。當(dāng)然,在實驗室的內(nèi)網(wǎng)環(huán)境中進(jìn)行開發(fā)測試,往往采用的是私有 IP 地址,這時可以通過 getByAddress 方法來構(gòu)造 InetAddress 實例。