1. 程式人生 > 其它 >Java篇:Java網路程式設計(二)網路地址及埠

Java篇:Java網路程式設計(二)網路地址及埠

2 網路地址及埠

2.1 網路地址

InetAddress類表示Internet協議(IP)地址,其包含兩個由final修飾的子類Inet4Address和Inet6Address分別表示IPv4地址和IPv6地址。

目前的全球因特網所採用的協議簇是TCP/IP協議族,IP是TCP/IP協議族中網路層的協議,是TCP/IP協議族的核心協議。目前IP協議的版本號是4(簡稱IPv4),發展至今已經使用了30多年。IPv4的地址位數為32位,也就是最多有2的32次方的電腦可以聯到Internet上,近十年來由於網際網路的蓬勃發展,IP地址的發放愈趨嚴格,各項資料顯示全球IPv4地址可能在2005至2008年間全部發完。

而IPv6是下一版本地網際網路協議,它地提出最初是因為隨著網際網路地迅速發展,IPv4定義的有限地址將被耗盡,地址空間的不足必將妨礙網際網路的近一步發展。

2.1.1 InetAddress

InetAddress的構造方法並不可直接訪問,而是通過提供的6個靜態方法返回InetAddress例項。不知道是否因為現在仍是以IPv4地址為主,以下靜態方法,預設優先返回的是IPv4地址。

InetAddress對域名進行解析是使用本地機器配置或者網路命名服務(如域名系統(Domain Name System,DNS)和網路資訊服務(Network Information Service,NIS))來實現。

INETADDRESS 構造方法:通過靜態方法返回
static InetAddress[] getAllByName(String host) 給定主機的名稱,根據系統上配置的名稱服務返回其IP地址陣列。
static InetAddress getByAddress(byte[] addr) 給出原始IP地址的 InetAddress物件。
static InetAddress getByAddress(String host, byte[] addr) 根據提供的主機名和IP地址建立InetAddress。
static InetAddress getByName(String host)
確定主機名稱的IP地址。
static InetAddress getLocalHost() 返回本地主機的地址。
static InetAddress getLoopbackAddress() 返回回送地址。

InetAddress類提供了對IP地址進行判斷的一些方法以及返回IP地址資訊的方法。

INETADDRESS 其他方法
boolean equals(Object obj) 將此物件與指定物件進行比較。
boolean isAnyLocalAddress() 檢查萬用字元地址中的InetAddress的實用程式。
boolean isLinkLocalAddress() 檢查InetAddress是否是連結本地地址的實用程式。
boolean isLoopbackAddress() 檢查InetAddress是否是一個環回地址的實用程式。
boolean isMCGlobal() 檢查多播地址是否具有全域性範圍的實用程式。
boolean isMCLinkLocal() 檢查組播地址是否具有鏈路範圍的實用程式。
boolean isMCNodeLocal() 檢查多播地址是否具有節點範圍的實用程式。
boolean isMCOrgLocal() 檢查組播地址是否具有組織範圍的實用程式。
boolean isMCSiteLocal() 檢查多播地址是否具有站點範圍的實用程式。
boolean isMulticastAddress() 檢查InetAddress是否是IP組播地址的實用程式。
boolean isReachable(int timeout) 測試該地址是否可達。
boolean isReachable(NetworkInterface netif, int ttl, int timeout) 測試該地址是否可達。
boolean isSiteLocalAddress() 檢查InetAddress是否是站點本地地址的實用程式。
byte[] getAddress() 返回此 InetAddress物件的原始IP地址。
String getCanonicalHostName() 獲取此IP地址的完全限定域名。
String getHostAddress() 返回文字顯示中的IP地址字串。
String getHostName() 獲取此IP地址的主機名。
String toString() 將此IP地址轉換為 String 。
int hashCode() 返回此IP地址的雜湊碼。

2.1.2 Inet4Address

Inet4Address作為InetAddress的直接子類,並沒有重寫構造方法。其支援的方法也與InetAddress相似。

INET4ADDRESS 方法
boolean equals(Object obj) 將此物件與指定物件進行比較。
byte[] getAddress() 返回此 InetAddress物件的原始IP地址。
String getHostAddress() 以文字表示形式返回IP地址字串。
int hashCode() 返回此IP地址的雜湊碼。
boolean isAnyLocalAddress() 檢查萬用字元地址中的InetAddress的實用程式。
boolean isLinkLocalAddress() 檢查InetAddress是否是連結本地地址的實用程式。
boolean isLoopbackAddress() 檢查InetAddress是否是一個環回地址的實用程式。
boolean isMCGlobal() 檢查多播地址是否具有全域性範圍的實用程式。
boolean isMCLinkLocal() 檢查組播地址是否具有鏈路範圍的實用程式。
boolean isMCNodeLocal() 檢查多播地址是否具有節點範圍的實用程式。
boolean isMCOrgLocal() 檢查組播地址是否具有組織範圍的實用程式。
boolean isMCSiteLocal() 檢查多播地址是否具有站點範圍的實用程式。
boolean isMulticastAddress() 檢查InetAddress是否是IP組播地址的實用程式。
boolean isSiteLocalAddress() 檢查InetAddress是否是站點本地地址的實用程式。

2.1.3 Inet6Address

同樣作為作為InetAddress的直接子類,Inet6Address卻有些不同。構造Inet6Address例項的方法必須通過傳入host、addr、scope_id/NetworkInterface nif來返回。

INET6ADDRESS 構造方法:通過靜態方法返回
static Inet6Address getByAddress(String host, byte[] addr, int scope_id) 在的確切方式建立Inet6Address, InetAddress.getByAddress(String,byte[])不同之處在於將IPv6 scope_id設定為給定數值。
static Inet6Address getByAddress(String host, byte[] addr, NetworkInterface nif) 在的確切方式建立Inet6Address, InetAddress.getByAddress(String,byte[])不同之處在於將IPv6 scope_id設定為對應於在指定的地址型別的給定介面的值 addr 。

INET6ADDRESS 其他方法
boolean equals(Object obj) 將此物件與指定物件進行比較。
byte[] getAddress() 返回此 InetAddress物件的原始IP地址。
NetworkInterface getScopedInterface() 如果此例項是使用範圍介面建立的,則返回範圍介面。
String getHostAddress() 返回文字顯示中的IP地址字串。
int getScopeId() 如果此例項與介面相關聯,則返回數字scopeId。
boolean isAnyLocalAddress() 檢查萬用字元地址中的InetAddress的實用程式。
boolean isIPv4CompatibleAddress() 檢查InetAddress是否與IPv4相容的IPv6地址的實用程式。
boolean isLinkLocalAddress() 檢查InetAddress是否是連結本地地址的實用程式。
boolean isLoopbackAddress() 檢查InetAddress是否是一個環回地址的實用程式。
boolean isMCGlobal() 檢查多播地址是否具有全域性範圍的實用程式。
boolean isMCLinkLocal() 檢查組播地址是否具有鏈路範圍的實用程式。
boolean isMCNodeLocal() 檢查多播地址是否具有節點範圍的實用程式。
boolean isMCOrgLocal() 檢查組播地址是否具有組織範圍的實用程式。
boolean isMCSiteLocal() 檢查多播地址是否具有站點範圍的實用程式。
boolean isMulticastAddress() 檢查InetAddress是否是IP組播地址的實用程式。
boolean isSiteLocalAddress() 檢查InetAddress是否是站點本地地址的實用程式。
int hashCode() 返回此IP地址的雜湊碼。

2.1.4 簡單應用

 
static void test1(){
        try {
​
​
            /* ********檢視cdn中百度域名對應的IP************************* */
            String hostname = "www.baidu.com";
            System.out.println("域名:"+hostname);
            InetAddress[] addresses = InetAddress.getAllByName(hostname);
​
            int[] countIp = {0,0};
​
            for(int i=0;i<addresses.length;i++){
                //統計IPv4地址的數量
                if (addresses[i] instanceof Inet4Address){
                    countIp[0]++;
                    System.out.println(String.format("IPv4地址%d:%s",countIp[0],addresses[i].getHostAddress()));
                }
                // 統計IPv6地址的資料量
                else if (addresses[i] instanceof Inet6Address){
                    countIp[1]++;
                    System.out.println(String.format("IPv6地址%d:%s",countIp[1],addresses[i].getHostAddress()));
                }
            }
            System.out.println(String.format("本機IPv4地址數量:%d,IPv6地址數量:%d\n\n",countIp[0],countIp[1]));
​
​
            /* **********************檢視本機地址*************************************** */
            // 獲取本機IP地址
            InetAddress localInet = InetAddress.getLocalHost();
            //獲取本機名稱
            String localHostname = localInet.getHostName();
            System.out.println("本機機名:"+localHostname);
​
            //根據本機名稱獲取本機全部ip(一般會包含IPv4,Ipv6的號碼)
            InetAddress[] localAdresses = InetAddress.getAllByName(localHostname);
            countIp[0]=0;
            countIp[1]=0;
​
​
            for(int i=0;i<localAdresses.length;i++){
                //統計IPv4地址的數量
                if (localAdresses[i] instanceof Inet4Address){
                    countIp[0]++;
                    System.out.println(String.format("IPv4地址%d:%s",countIp[0],localAdresses[i].getHostAddress()));
                }
                // 統計IPv6地址的資料量
                else if (localAdresses[i] instanceof Inet6Address){
                    countIp[1]++;
                    System.out.println(String.format("IPv6地址%d:%s",countIp[1],localAdresses[i].getHostAddress()));
                }
            }
            System.out.println(String.format("本機IPv4地址數量:%d,IPv6地址數量:%d\n\n",countIp[0],countIp[1]));
​
​
            /* ***********************Inet6Address************************ */
            /* IPv6測試的樣例好像只能找到自己本機的地址 localAdresses*/
            int inet6AddressScopeId=0;
            String inet6AddressHostname="";
            byte[] inet6AddressS={0};
​
            for(int i=0;i<localAdresses.length;i++){
                // 獲取IPv6地址
                if (localAdresses[i] instanceof Inet6Address){
​
                    inet6AddressScopeId = ((Inet6Address) localAdresses[i]).getScopeId();
                    inet6AddressHostname = localAdresses[i].getHostName();
                    inet6AddressS = localAdresses[i].getAddress();
                    break;
                }
            }
            Inet6Address inet6Address = Inet6Address.getByAddress(inet6AddressHostname,inet6AddressS,inet6AddressScopeId);
            System.out.println(String.format("IPv6地址:%s",inet6Address.getHostAddress()));
​
            System.out.println(inet6Address.isIPv4CompatibleAddress());
​
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

2.2 網路地址+埠

2.2.1 SocketAddress

這個類代表一個沒有協議附件的Socket地址。 作為一個抽象類,它的意思是使用特定的,依賴於協議的實現進行子類化。

它提供了用於繫結,連線或返回值的套接字所使用的不可變物件。

2.2.2 InetSocketAddress

2.2.2.1 InetSocketAddress

該類實現IP套接字地址(IP地址+埠號)它也可以是一對(主機名+埠號),在這種情況下將嘗試解析主機名。 如果解決方案失敗,那麼該地址被認為是未解決的,但在某些情況下仍可以使用,例如通過代理連線。

它提供了用於繫結,連線或返回值的套接字所使用的不可變物件。

萬用字元是一個特殊的本地IP地址。 通常意味著“任何”,只能用於bind操作。

構造方法
InetSocketAddress(InetAddress addr, int port) 從IP地址和埠號建立套接字地址。
InetSocketAddress(int port) 建立一個套接字地址,其中IP地址為萬用字元地址,埠號為指定值。
InetSocketAddress(String hostname, int port) 從主機名和埠號建立套接字地址。
MODIFIER AND TYPEMETHOD AND DESCRIPTION
static InetSocketAddress createUnresolved(String host, int port) 從主機名和埠號建立未解析的套接字地址。
InetAddress getAddress() 獲得 InetAddress 。
boolean equals(Object obj) 將此物件與指定物件進行比較。
String getHostName() 獲得 hostname 。
String getHostString() 如果沒有主機名(使用文字建立),則返回主機名或地址的String形式。
int getPort() 獲取埠號。
boolean isUnresolved() 檢查地址是否已解析成功。
int hashCode() 返回該套接字地址的雜湊碼。
String toString() 構造此InetSocketAddress的字串表示形式。
2.2.2.2 程式碼應用
   static void test2(){
​
        InetSocketAddress inetSocketAddress = new InetSocketAddress(9999);
        System.out.println(inetSocketAddress);
        System.out.println(inetSocketAddress.isUnresolved()+"\n\n");
​
        try {
            InetAddress localInet = InetAddress.getLocalHost();
            inetSocketAddress = new InetSocketAddress(localInet,9999);
            System.out.println(inetSocketAddress);
            System.out.println(inetSocketAddress.isUnresolved()+"\n\n");
​
            inetSocketAddress = InetSocketAddress.createUnresolved(localInet.getHostName(),9999);
            System.out.println(inetSocketAddress);
            System.out.println(inetSocketAddress.isUnresolved()+"\n\n");
​
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
​
​
    }

2.2.3 InterfaceAddress

此類表示網路介面地址。 簡而言之,當地址是IPv4地址時,它是一個IP地址,一個子網掩碼和一個廣播地址。 在IPv6地址的情況下,IP地址和網路字首長度。

InterfaceAddress似乎並沒有提供構造方法,一般來說應該是通過其他類來進行構建,比如NetworkInterface。

INTERFACEADDRESS包含的方法
InetAddress getAddress() 返回此地址的 InetAddress 。
InetAddress getBroadcast() InetAddress的廣播地址返回InetAddress。
short getNetworkPrefixLength() 返回此地址的網路字首長度。
boolean equals(Object obj) 將此物件與指定物件進行比較。
int hashCode() 返回此介面地址的雜湊碼。
String toString() 將此介面地址轉換為 String 。

2.2.4 NetworkInterface

2.2.4.1 NetworkInterface

此類表示由名稱組成的網路介面和分配給此介面的IP地址列表。 用於標識組播組所在的本地介面。 介面通常由諸如“le0”的名稱所知。

NETWORKINTERFACE包含的方法
static Enumeration<NetworkInterface> getNetworkInterfaces() 返回本機上的所有介面。
static NetworkInterface getByIndex(int index) 獲取一個網路介面給它的索引。
static NetworkInterface getByInetAddress(InetAddress addr) 搜尋具有繫結到指定的Internet協議(IP)地址的網路介面的便利方法。
static NetworkInterface getByName(String name) 搜尋具有指定名稱的網路介面。
String getDisplayName() 獲取此網路介面的顯示名稱。
byte[] getHardwareAddress() 返回介面的硬體地址(通常為MAC),如果它有一個,如果可以訪問給定當前許可權。
int getIndex() 返回此網路介面的索引。
Enumeration<InetAddress> getInetAddresses() 使用繫結到此網路介面的InetAddresses全部或一部分子列舉的列舉方法。
List<InterfaceAddress> getInterfaceAddresses() 獲取此網路介面的 InterfaceAddresses的全部或部分的列表。
int getMTU() 返回此介面的最大傳輸單元(MTU)。
String getName() 獲取此網路介面的名稱。
NetworkInterface getParent() 返回此介面的父NetworkInterface;如果這是一個子介面,或 null如果它是一個物理(非虛擬的)介面或沒有父。
Enumeration<NetworkInterface> getSubInterfaces() 獲取連線到此網路介面的所有子介面(也稱為虛擬介面)的列舉。
boolean isLoopback() 返回網路介面是否是環回介面。
boolean isPointToPoint() 返回網路介面是否是點對點介面。
boolean isUp() 返回網路介面是否啟動並執行。
boolean isVirtual() 返回此介面是否為虛擬介面(也稱為子介面)。
boolean supportsMulticast() 返回網路介面是否支援多播。
boolean equals(Object obj) 將此物件與指定物件進行比較。
String toString() 返回物件的字串表示形式。
int hashCode() 返回物件的雜湊碼值。
2.2.4.2 簡單應用
  • NetworkInterface的構造方法,通過getNetworkInterfaces()返回本機全部埠,每一個NetworkInterface都會包含索引(index)、地址(Adress)、名稱(Name),獲取這些資訊就可以通過其他三個構造方法來建立對應的NetworkInterface例項。

   static void test3(){
        try {
            //返回本機上所有埠
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
​
            while (networkInterfaces.hasMoreElements()){
                NetworkInterface Ninterface = networkInterfaces.nextElement();
                System.out.println("埠資訊:"+Ninterface);
                System.out.println(String.format(
                        "介面的最大傳輸單元(MTU):%d,是否環回介面:%b,是否是點對點介面:%b,是否啟動並執行:%b,是否為虛擬介面(也稱為子介面):%b,否支援多播:%b",
                        Ninterface.getMTU(),
                        Ninterface.isLoopback(),
                        Ninterface.isPointToPoint(),
                        Ninterface.isUp(),
                        Ninterface.isVirtual(),
                        Ninterface.supportsMulticast()
                ));
​
​
                //獲取硬體地址
                if(Ninterface.getHardwareAddress()!=null){
                    StringBuilder mac = new StringBuilder();
​
                    byte[] f = Ninterface.getHardwareAddress();
                    for(int i=0;i<f.length;i++){
                        String t = Integer.toHexString(0xff & f[i]);
                        if(t.length()==1) mac.append("0"+t);
                        else mac.append(t);
​
                        if(i!=f.length-1) mac.append("-");
​
                    }
                    System.out.println("硬體地址(如果有):"+mac);
                }
​
                //獲取子介面
                Enumeration<NetworkInterface> subInterfaces = Ninterface.getSubInterfaces();
​
                int subc=0;
​
                while (subInterfaces.hasMoreElements()){
                    NetworkInterface subInterface = subInterfaces.nextElement();
                    //System.out.println("埠資訊:"+subInterface);
                    subc++;
                }
                System.out.println("子介面個數:"+subc);
​
                //getInetAddresses
​
                Enumeration<InetAddress> inetAddressEnumeration = Ninterface.getInetAddresses();
                while (inetAddressEnumeration.hasMoreElements()){
                    System.out.println("對應的InetAddress:"+inetAddressEnumeration.nextElement());
                }
​
                //List<InterfaceAddress> getInterfaceAddresses()
​
                List<InterfaceAddress> interfaceAddressList = Ninterface.getInterfaceAddresses();
​
                for(int i=0;i<interfaceAddressList.size();i++){
                    System.out.println("對應的InterfaceAddress:"+interfaceAddressList.get(i));
                }
​
​
​
                System.out.println("\n");
            }
​
            //返回百度的埠--無法獲取資訊
            String hostname = "www.baidu.com";
            System.out.println("域名:"+hostname);
            InetAddress addresse = InetAddress.getByName(hostname);
            System.out.println("InetAddress:"+addresse);
​
            NetworkInterface networkInterface = NetworkInterface.getByInetAddress(addresse);
​
            System.out.println("NetworkInterface:"+networkInterface);
​
​
​
​
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

2.X 參考

當你深入瞭解,你就會發現世界如此廣袤,而你對世界的瞭解則是如此淺薄,請永遠保持謙卑的態度。