国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

重拾Java Network Programming(二)InetAddress

daryl / 1656人閱讀

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

前言

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

InetAddress

NetworkInterface

具體應用范例

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

InetAddress API

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

IP,IPv4,IPv6

單播,多播,廣播

loop地址

域名

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

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

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

NetworkInterface API

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

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

當我們啟動web應用時,我們往往會從HTTP報文中獲取訪客的IP并且將其記錄進日志中。從而可以從日志中分析常見的訪客或是不明訪客。這里我們將獲取一個手動生成的包含IP地址的日志文件,并且將其中的IP地址轉化為hostName輸出。這里我們將采用多線程實現(xiàn),因為讀取一條IP記錄的速度遠遠高于從DNS服務器獲取域名的速度。

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

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();
       }
    }
}

一個處理LOG的IPAnalyser類,該類實現(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;
    }
}

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

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() + "對應的主機名為" + logEntry.getHostName().get());
                writeCount++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }

    }
}

實體類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和相關的所有線程:

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();
    }
}

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

參考書籍
Java Network Programming 4th Edition


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

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

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76366.html

相關文章

  • 重拾Java Network Programming(一)IO流

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

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

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

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

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

    魏明 評論0 收藏0
  • JAVA網(wǎng)絡程序設計基礎(筆記)

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

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

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

    Shihira 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<