成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

重拾Java Network Programming(二)InetAddress

daryl / 1668人閱讀

摘要:前言今天,我將梳理在網(wǎng)絡(luò)編程中很重要的一個(gè)類以及其相關(guān)的類。這類主機(jī)通常不需要外部互聯(lián)網(wǎng)服務(wù),僅有主機(jī)間相互通訊的需求。可以通過該接口獲取所有本地地址,并根據(jù)這些地址創(chuàng)建。在這里我們使用阻塞隊(duì)列實(shí)現(xiàn)主線程和打印線程之間的通信。

前言

今天,我將梳理在Java網(wǎng)絡(luò)編程中很重要的一個(gè)類InetAddress以及其相關(guān)的類NetworkInterface。在這篇文章中將會(huì)涉及:

InetAddress

NetworkInterface

具體應(yīng)用范例

這里的范例將會(huì)實(shí)現(xiàn)一個(gè)簡單的日志IP解析系統(tǒng)。我們將會(huì)在后面詳細(xì)介紹。

InetAddress API

在此我將會(huì)直接從API入手,如果對(duì)其中的名詞有何疑惑,可以先行了解一下基礎(chǔ)概念。
需要先行了解的概念包括:

IP,IPv4,IPv6

單播,多播,廣播

loop地址

域名

public class InetAddress{
    //私有化構(gòu)造器,我們只能通過其提供的靜態(tài)工廠方法來獲取一個(gè)實(shí)例
    //同時(shí)我們也不可以修改內(nèi)部的IP地址或是域名
    //這種Immutable的方式確保了其線程安全性
    
    //這里需要注意java沒有正整數(shù)型,因此我們需要對(duì)開頭為1的二進(jìn)制數(shù)進(jìn)行轉(zhuǎn)義,如下
    //byte[] address = {107, 23, (byte) 216, (byte) 196};
    public static InetAddress getByAddress(byte[] addr) throws UnknownHostException;
    //該方法不會(huì)查詢DNS來確保域名和IP地址相符
    //這里有一個(gè)比較有意思的在于如果你希望尋找家用設(shè)備如打印機(jī)等的局域網(wǎng)地址,則可以通過遍歷254個(gè)可能的局域網(wǎng)地址來找到它,而不需要將其硬編碼進(jìn)代碼中
    public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException;
    //根據(jù)域名獲取一個(gè)實(shí)例,該加載為懶加載,即除非到必要的時(shí)候,否則將不會(huì)啟動(dòng)DNS查詢
    public static InetAddress getByName(String host) throws UnknownHostException;
    
    //獲取該域名對(duì)應(yīng)的所有IP地址(即一個(gè)域名可以映射到多個(gè)IP地址)
    public static InetAddress[] getAllByName(String host)
                                  throws UnknownHostException
    
    //獲取環(huán)回地址,通常為172.0.0.1                              
    public static InetAddress getLoopbackAddress();
    //獲取本機(jī)的IP地址,如果本機(jī)沒有聯(lián)網(wǎng),則返回環(huán)回地址
    public static InetAddress getLoaclHost();
    
    //獲取主機(jī)名
    public String getHostName()
    //獲取主機(jī)別名
    public String getCanonicalHostName() 
    //獲取主機(jī)的IP地址
    //該方法可以用來判斷是IPv4地址還是IPv6地址
    public byte[] getAddress()
    //獲取String類型的IP地址
    public String getHostAddress()
    
    //是否是一個(gè)和本地主機(jī)相關(guān)的地址
    //包括本機(jī)IP,loopback,wifi地址等
    public boolean isAnyLocalAddress() 
    //是否是環(huán)回地址
    public boolean isLoopbackAddress() 
    //是否是鏈路本地地址
    //鏈路本地地址(Link-local address)是計(jì)算機(jī)網(wǎng)絡(luò)中一類特殊的地址,
    //它僅供于在網(wǎng)段,或廣播域中的主機(jī)相互通信使用。
    //這類主機(jī)通常不需要外部互聯(lián)網(wǎng)服務(wù),僅有主機(jī)間相互通訊的需求。
    public boolean isLinkLocalAddress() 
    //是否落入這三個(gè)網(wǎng)段
    //10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
    public boolean isSiteLocalAddress() 
    //是否是廣播地址
    public boolean isMulticastAddress() 
    //是否是全球通用的廣播地址
    public boolean isMCGlobal()
    //是否是企業(yè)專屬的多播地址
    public boolean isMCOrgLocal()
    
    //判斷當(dāng)前節(jié)點(diǎn)是否可以訪問目標(biāo)節(jié)點(diǎn)
    //通常使用ICMP報(bào)文實(shí)現(xiàn)
    public boolean isReachable(int timeout) throws IOException
    public boolean isReachable(NetworkInterface interface, int ttl, int timeout) throws IOException

    //只要兩個(gè)對(duì)象的IP地址相等,則二者相等(與域名無關(guān))
    public boolean equals(Object o) 
    //僅根據(jù)IP地址計(jì)算hashCode
    public int hashCode()
    //格式為 “域名/IP地址”
    public String toString()
}

相關(guān)參數(shù):
networkaddress.cache.negative.ttl:失敗的DNS查找被緩存的時(shí)間
networkaddress.cache.ttl:成功的DNS查找被緩存的時(shí)間

NetworkInterface API

NetworkInterface代表一個(gè)本地的IP地址??梢酝ㄟ^該接口獲取所有本地地址,并根據(jù)這些地址創(chuàng)建InetAddress。通過NetworkInterface接口,可以獲取本機(jī)配置的網(wǎng)絡(luò)接口的名字,IP列表(包括IPV4和IPV6),網(wǎng)卡地址,最大傳輸單元(MTU),接口狀態(tài)(開啟/關(guān)閉)、接口網(wǎng)絡(luò)類型(點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)、回環(huán)網(wǎng)絡(luò))等信息

public final class NetworkInterface{
    //根據(jù)名稱獲取網(wǎng)絡(luò)接口
    //該方法依賴于底層平臺(tái)
    public static NetworkInterface getByName(String name) throws SocketException
    //根據(jù)IP地址獲得對(duì)應(yīng)的網(wǎng)絡(luò)接口
    public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException
    //獲取所有的網(wǎng)絡(luò)接口
    public static Enumeration getNetworkInterfaces() throws SocketException
    //獲取該接口之下所有的IP地址
    public Enumeration getInetAddresses()
    //獲取MAC地址
    public byte[] getHardwareAddress()
}
獲取WebLog中的IP地址對(duì)應(yīng)的hostName

當(dāng)我們啟動(dòng)web應(yīng)用時(shí),我們往往會(huì)從HTTP報(bào)文中獲取訪客的IP并且將其記錄進(jìn)日志中。從而可以從日志中分析常見的訪客或是不明訪客。這里我們將獲取一個(gè)手動(dòng)生成的包含IP地址的日志文件,并且將其中的IP地址轉(zhuǎn)化為hostName輸出。這里我們將采用多線程實(shí)現(xiàn),因?yàn)樽x取一條IP記錄的速度遠(yuǎn)遠(yuǎn)高于從DNS服務(wù)器獲取域名的速度。

首先我們使用工具類向文件中寫入日志:

public class Util {

    private static final String filePath = "YOUR_FILE_PATH";
    private static final String[] hostNames = new String[]{
            "www.sina.com",
            "www.sohu.com",
            "www.taobao.com",
            "www.baidu.com",
            "www.qq.com",
            "www.163.com",
            "www.dzone.com",
            "www.github.com",
            "www.acmcoder.com",
            "www.meituan.com",
            "kafka.apachecn.org",
            "www.ibm.com",
            "javarevisited.blogspot.kr"
    };
    public static void main(String[] args){
        int count = 0;
       try (BufferedWriter bf = new BufferedWriter(new FileWriter(filePath))){
           for(String host : hostNames){
               InetAddress[] addresses = InetAddress.getAllByName(host);
               count+= addresses.length;
               for (InetAddress address : addresses) {
                   bf.write(address.getHostAddress() + " " + address.getHostName());
                   bf.newLine();
               }
           }
           System.out.println(count);
       } catch (IOException e) {
           e.printStackTrace();
       }
    }
}

一個(gè)處理LOG的IPAnalyser類,該類實(shí)現(xiàn)Callable接口,支持將內(nèi)部的值返回給別的線程使用:

public class IPAnalyser implements Callable{
    private String logItem;
    public IPAnalyser(String logItem){
        this.logItem = logItem;
    }
    @Override
    public String call() throws Exception {
        if (logItem!=null){
            String[] items = logItem.split(" ");
            InetAddress inetAddress = InetAddress.getByName(items[0]);
            return inetAddress.getHostAddress();
        }
        return null;
    }
}

額外使用一個(gè)線程來同步處理IPAnalyser返回的值,從而避免因?yàn)槿罩疚募^大,日志條目全部存儲(chǔ)在主存中,再一次性讀取而帶來因占用大量內(nèi)存而影響性能的問題。
在這里我們使用阻塞隊(duì)列實(shí)現(xiàn)主線程和打印線程之間的通信。但是我們需要在打印完該日志文件后,結(jié)束該打印線程,因此使用write來記錄當(dāng)前已經(jīng)打印的日志條目數(shù),然后在打印完成所有的之后結(jié)束該線程。

public class IPPrinter implements Runnable {
    private BlockingQueue queue;
    private static volatile int writeCount;
    public IPPrinter(BlockingQueue queue){
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true){
            if (writeCount == Main.readCount){
                System.out.println("寫完畢");
                break;
            }
            try {
                LogEntry logEntry = queue.take();
                System.out.println(logEntry.getOrigin() + "對(duì)應(yīng)的主機(jī)名為" + logEntry.getHostName().get());
                writeCount++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

    }
}

實(shí)體類LogEntry保存原來的日志條目和解析后的日志線程返回:

public class LogEntry {
    private Future hostName;

    private String origin;

    public LogEntry(Future hostName, String origin){
        this.hostName = hostName;
        this.origin = origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
    }

    public String getOrigin() {
        return origin;
    }

    public Future getHostName() {
        return hostName;
    }

    public void setHostName(Future hostName) {
        this.hostName = hostName;
    }
}

最后在主線程中開啟IO和相關(guān)的所有線程:

public class Main {
    private static final String filePath = "/Users/rale/IdeaProjects/Demo/concurrency/src/main/java/cn/deerowl/weblog_analyse/web.log";
    private static final BlockingQueue queue = new LinkedBlockingQueue<>();

    public static volatile int readCount  = 30;

    public static void main(String[] args){
        ExecutorService executorService = Executors.newFixedThreadPool(6);
        executorService.submit(new IPPrinter(queue));
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))){
            String tmp;
            while ((tmp = bufferedReader.readLine()) != null){
                Future f = executorService.submit(new IPAnalyser(tmp));
                queue.put(new LogEntry(f, tmp));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        executorService.shutdown();
    }
}

這里要強(qiáng)調(diào)一下域名和主機(jī)名的關(guān)聯(lián):一個(gè)域名之下可以有多個(gè)主機(jī)名,如域名abc.com下,有主機(jī)server1和server2,其主機(jī)全名就是server1.abc.com和server2.abc.com。

參考書籍
Java Network Programming 4th Edition


想要了解更多開發(fā)技術(shù),面試教程以及互聯(lián)網(wǎng)公司內(nèi)推,歡迎關(guān)注我的微信公眾號(hào)!將會(huì)不定期的發(fā)放福利哦~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76366.html

相關(guān)文章

  • 重拾Java Network Programming(一)IO流

    摘要:不同類型的流入,往往對(duì)應(yīng)于不同類型的流數(shù)據(jù)。所以通常會(huì)將字節(jié)緩存到一定數(shù)量后再發(fā)送。如果是,則將兩個(gè)標(biāo)記都拋棄并且將之前的內(nèi)容作為一行返回。因此二者陷入死鎖。因此推出了和類。 前言 最近在重拾Java網(wǎng)絡(luò)編程,想要了解一些JAVA語言基本的實(shí)現(xiàn),這里記錄一下學(xué)習(xí)的過程。 閱讀之前,你需要知道 網(wǎng)絡(luò)節(jié)點(diǎn)(node):位于網(wǎng)絡(luò)上的互相連通的設(shè)備,通常為計(jì)算機(jī),也可以是打印機(jī),網(wǎng)橋,路由器等...

    Lycheeee 評(píng)論0 收藏0
  • 重拾Java Network Programming(四)URLConnection & C

    摘要:從而一方面減少了響應(yīng)時(shí)間,另一方面減少了服務(wù)器的壓力。表明響應(yīng)只能被單個(gè)用戶緩存,不能作為共享緩存即代理服務(wù)器不能緩存它。這種情況稱為服務(wù)器再驗(yàn)證。否則會(huì)返回響應(yīng)。 前言 本文將根據(jù)最近所學(xué)的Java網(wǎng)絡(luò)編程實(shí)現(xiàn)一個(gè)簡單的基于URL的緩存。本文將涉及如下內(nèi)容: HTTP協(xié)議 HTTP協(xié)議中與緩存相關(guān)的內(nèi)容 URLConnection 和 HTTPURLConnection Respo...

    Guakin_Huang 評(píng)論0 收藏0
  • 重拾Java Network Programming(四)URLConnection & C

    摘要:從而一方面減少了響應(yīng)時(shí)間,另一方面減少了服務(wù)器的壓力。表明響應(yīng)只能被單個(gè)用戶緩存,不能作為共享緩存即代理服務(wù)器不能緩存它。這種情況稱為服務(wù)器再驗(yàn)證。否則會(huì)返回響應(yīng)。 前言 本文將根據(jù)最近所學(xué)的Java網(wǎng)絡(luò)編程實(shí)現(xiàn)一個(gè)簡單的基于URL的緩存。本文將涉及如下內(nèi)容: HTTP協(xié)議 HTTP協(xié)議中與緩存相關(guān)的內(nèi)容 URLConnection 和 HTTPURLConnection Respo...

    魏明 評(píng)論0 收藏0
  • JAVA網(wǎng)絡(luò)程序設(shè)計(jì)基礎(chǔ)(筆記)

    摘要:三端口與套接字端口指一臺(tái)計(jì)算機(jī)只有單一的連接到網(wǎng)絡(luò)的物理連接,所以的數(shù)據(jù)都通過此連接對(duì)內(nèi)對(duì)外送達(dá)特定的計(jì)算機(jī),這就是端口。三程序設(shè)計(jì)由上面可知基于的信息傳遞速度更快。接收數(shù)據(jù)包使用創(chuàng)建數(shù)據(jù)包套接字,綁定指定端口。 服務(wù)器 網(wǎng)絡(luò) 客戶機(jī) 第一部分 一.局域網(wǎng)與因特網(wǎng) 服務(wù)器是指提供信息的計(jì)算機(jī)或程序,...

    PAMPANG 評(píng)論0 收藏0
  • Java網(wǎng)絡(luò)編程-你是GG還是MM?

    摘要:網(wǎng)絡(luò)層主要將從下層接收到的數(shù)據(jù)進(jìn)行地址例的封裝與解封裝。會(huì)話層通過傳輸層端口號(hào)傳輸端口與接收端口建立數(shù)據(jù)傳輸?shù)耐贰? 第六階段 網(wǎng)絡(luò)編程 每一臺(tái)計(jì)算機(jī)通過網(wǎng)絡(luò)連接起來,達(dá)到了數(shù)據(jù)互動(dòng)的效果,而網(wǎng)絡(luò)編程所解決的問題就是如何讓程序與程序之間實(shí)現(xiàn)數(shù)據(jù)的通訊與互動(dòng)在嗎?你是GG還是MM? (一) 網(wǎng)絡(luò)模型概述 (1) 兩大模型 網(wǎng)絡(luò)模型一般是指: OSI(Open System Inter...

    Shihira 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<