溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java判斷ip是否為IPV4或IPV6地址的方式有哪些

發(fā)布時間:2023-03-02 11:56:44 來源:億速云 閱讀:194 作者:iii 欄目:開發(fā)技術

今天小編給大家分享一下Java判斷ip是否為IPV4或IPV6地址的方式有哪些的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    判斷字符串是否為IP地址通常都是基于正則表達式實現(xiàn)的,無論是引入外部的依賴包亦或是自己寫正則實現(xiàn),基本都是基于正則表達式實現(xiàn)的判斷。然而比較例外的是,jdk自身提供了Inet4Address.getByName方法也可以幫助我們實現(xiàn)ip地址的判斷。

    一、判斷是否為IPV4,IPV6地址的常見方式

    1. 使用Apache Commons Validator做判斷

    需要引入依賴包

        <dependency>
          <groupId>commons-validator</groupId>
          <artifactId>commons-validator</artifactId>
          <version>1.6</version>
        </dependency>

    有了依賴包,后續(xù)調用InetAddressValidator的核心API就好了。

    1.1判斷是否為IPV4地址

        private static final InetAddressValidator VALIDATOR = InetAddressValidator.getInstance();
        public static boolean isValidIPV4ByValidator(String inetAddress) {
            return VALIDATOR.isValidInet4Address(inetAddress);
        }

    1.2判斷是否為IPV6地址

        public static boolean isValidIPV6ByValidator(String inetAddress) {
            return VALIDATOR.isValidInet6Address(inetAddress);
        }

    1.3判斷是否為IPV6或者IPV4地址

        public static boolean isValidIPV6ByValidator(String inetAddress) {
            return VALIDATOR.isValid(inetAddress);
        }

    2. 使用Guava做判斷

    引入依賴包

        <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>30.0-jre</version>
        </dependency>

    調用InetAddresses.isInetAddress即可實現(xiàn)快速的判斷,但這個方式能同時判斷字符串是否為IPV4或者IPV6地址,如果你只想判斷其中一種格式,那就不行了。

        public static boolean isValidByGuava(String ip) {
            return InetAddresses.isInetAddress(ip);
        }

    3. 使用OWASP正則表達式做判斷

    OWASP提供了一系列用于校驗常見web應用名詞的正則表達式,通過OWASP_Validation_Regex_Repository你可以檢索到他們。這個判斷方式只能判斷是否為IPV4地址。

        private static final String OWASP_IPV4_REGEX =
                "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
                        "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
                        "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
                        "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
    
        private static final Pattern OWASP_IPv4_PATTERN = Pattern.compile(OWASP_IPV4_REGEX);
    
        public static boolean isValidIPV4ByOWASP(String ip) {
            if (ip == null || ip.trim().isEmpty()) {
                return false;
            }
            return OWASP_IPv4_PATTERN.matcher(ip).matches();
        }

    4. 使用自定義正則表達式做判斷

    如下通過自定義的正則表達式判斷字符串是否為IPV4地址,它的正則表達式以及實現(xiàn)細節(jié),其實和第一種方案中判斷IPV4是一致的,如果你只想判斷字符串是否為IPV4地址,又懶得引入外部包,那么3,4這兩種方式適合你。

        private static final String IPV4_REGEX =
                "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";
    
        private static final Pattern IPv4_PATTERN = Pattern.compile(IPV4_REGEX);
    
        public static boolean isValidIPV4ByCustomRegex(String ip) {
            if (ip == null || ip.trim().isEmpty()) {
                return false;
            }
            if (!IPv4_PATTERN.matcher(ip).matches()) {
                return false;
            }
            String[] parts = ip.split("\\.");
            try {
                for (String segment : parts) {
                    if (Integer.parseInt(segment) > 255 ||
                            (segment.length() > 1 && segment.startsWith("0"))) {
                        return false;
                    }
                }
            } catch (NumberFormatException e) {
                return false;
            }
            return true;
        }

    5. 使用JDK內置的Inet4Address做判斷

    JDK從1.4版本開始就提供了Inet4Address類實現(xiàn)對IP的各項校驗操作,結合該類的getByNamegetHostAddress方法可實現(xiàn)IP地址判斷,但是頻繁的調用這兩個方法會產生一定的性能問題。以下是通過JDK判斷字符串是否為IPV4地址的方式:

        public static boolean isValidIPV4ByJDK(String ip) {
            try {
                return Inet4Address.getByName(ip)
                        .getHostAddress().equals(ip);
            } catch (UnknownHostException ex) {
                return false;
            }
        }

    二、并不適合ping命令

    1. IPV4的標準格式

    本文列舉的幾種判斷方式都是針對標準的IP地址而言,標準指的是IP地址由4位通過逗號分割的8bit長度的數(shù)字字符串組成,由于每位數(shù)字只有8bit長度,所以每個數(shù)字的值應該在0~255范圍內。相關文檔可以參考RFC5321。

    Java判斷ip是否為IPV4或IPV6地址的方式有哪些

    2. 有效性驗證

    我們選舉幾組字符串,有缺少位數(shù)的,有數(shù)字以0開頭的,也有一組是符合標準格式的。然后通過之前列舉的方法判斷是否為有效的IP地址。

    測試過程就不再贅述,直接將測試用例和測試結果匯總成如下的表格:

    用例isValidIPV4ByValidatorisValidIPV6ByValidatorisValidByGuavaisValidIPV4ByOWASPisValidIPV4ByCustomRegexisValidIPV4ByJDK
    172.8.9.28truefalsetruetruetruetrue
    192.168.0.072falsefalsefalsetruefalsefalse
    172.08.9.28falsefalsefalsetruefalsefalse
    172.9.28falsefalsefalsefalsefalsefalse
    192.168.072falsefalsefalsefalsefalsefalse
    192.168.1falsefalsefalsefalsefalsefalse
    2001:0db8:85a3:0000:0000:8a2e:0370:7334falsetruetruefalsefalsefalse

    通過這7個測試用例中,不難看出:

    • 第1個IP剛好是4位,每位都在0~255之間,且沒有任何一位以0開頭。所有判斷IPV4的方法都返回了true,符合預期。

    • 第2,3個IP也都是4位地址,但是某一位出現(xiàn)以0開始的數(shù)字,此時采用OWASP正則表達式的方式返回了true,其他方法都返回了false。

    • 第4,5,6個IP都是3位地址,所有方法返回了false。

    • 最后一個是合法的ipv6地址,我們通過Apache Commons Validator或者Guava包提供的判斷方法能夠正常返回true。

    3. 性能對比

    本文在列舉的第5個判斷方法時特意提到了性能問題,那么使用Inet4Address判斷IP地址到底會導致多大的性能損耗呢?實驗證明,當判斷使用大規(guī)模非法IP地址做輸入,該方法的性能損耗將不敢想象!

    下面將通過一項測試來驗證這個結論。

        private static List<String> generateFakeIp(int capacity) {
            List<String> ipList = new ArrayList<String>(capacity);
            for (int i = 0; i < capacity; i++) {
                int parts = boundRandom(1, 3);
                if (chanceOf50()) { //each ip has 50% chance to be 4 parts
                    parts = 4;
                }
                StringBuilder sbBuilder = new StringBuilder();
                for (int j = 0; j < parts; j++) {
                    if (sbBuilder.length() > 0) {
                        sbBuilder.append(".");
                    }
                    StringBuilder stringBuilder = new StringBuilder();
                    if (chanceOf10()) { //each part has 10% chance to generate a fake number
                        stringBuilder.append('a');
                    } else { //each part has 90% chance to generate the correct number
                        stringBuilder.append(boundRandom(0, 255));
                    }
                    sbBuilder.append(stringBuilder);
                }
                ipList.add(sbBuilder.toString());
            }
            return ipList;
        }
        
        private static long correctCount(List<String> ipList) {
            return ipList.stream().filter(ip -> isValidIPV4ByCustomRegex(ip)).collect(Collectors.toList()).size();
        }
        
        // 50% chance
        private static boolean chanceOf50() {
            return boundRandom(0, 9) < 5;
        }
    
        // 10% chance
        private static boolean chanceOf10() {
            return boundRandom(0, 9) < 1;
        }
    
        private static Random random = new Random();
        // random int between [start, end], both start and end are included
        private static int boundRandom(int start, int end) {
            return start + random.nextInt(end);
        }

    我們通過上面的generateFakeIp方法來產生一批隨機的IP地址,這些IP中有正確格式的,也有非法格式的。

    主體測試方法如下,該方法將比較isValidIPV4ByCustomRegexisValidIPV4ByJDK這兩種判斷IP地址的總耗時,以分析性能問題。

        public static void performanceTest() {
            List<String> ipList = generateFakeIp(100);
            double chance = correctCount(ipList);
            System.out.println("start testing, correct ip count is : " + chance);
            long t1 = System.currentTimeMillis();
            ipList.stream().forEach( ip-> isValidIPV4ByCustomRegex(ip));
            long t2 = System.currentTimeMillis();
            ipList.stream().forEach( ip-> isValidIPV4ByJDK(ip));
            long t3 = System.currentTimeMillis();
            System.out.println("isValidIPV4ByCustomRegex cost time : " + (t2-t1));
            System.out.println("isValidIPV4ByJDK cost time : " + (t3-t2));
        }

    直接運行后,打印以下結果。

    start testing, correct ip count is : 37.0
    isValidIPV4ByCustomRegex cost time : 2
    isValidIPV4ByJDK cost time : 13745

    可以看到,當100個IP中只有37個是合法IP時,基于正則表達式的判斷方法只用了2ms,而基于JDK內置的Inet4Address實現(xiàn)的判斷方法卻用了13s,這已經不在在同一個數(shù)量級了。如果我們將測試基數(shù)再擴大,那更加不敢想象,所以實際工作中,千萬不要使用Inet4Address來做IP合法性判斷。

    4. 判斷IPV4的方法并不適合ping命令

    對于標準IPV4格式的地址來說,以上判斷方式是沒問題的,但是部分非標準IPV4格式的地址,卻能夠被ping命令正常解析。

    對于ping命令來說,我們這里列舉的第2~6個IP地址都是合法的,能夠被正常解析。

    不妨驗證一下:

    Java判斷ip是否為IPV4或IPV6地址的方式有哪些

    可以看出,當我們輸入的IP地址中,某一位數(shù)字位以0開頭,那么也能被正常解析,從圖片可以看出192.168.0.072被解析成了192.168.0.58,172.08.9.28被解析成了172.08.9.28。這是為什么呢?

    當ping命令接收的IP地址中,出現(xiàn)以0開頭的數(shù)字位,那么ping命令將嘗試以八進制解析該位,八進制的072,即對應十進制的58,所以192.168.0.072就被解析成了192.168.0.58

    如果以0開頭的數(shù)字位,不符合八進制的格式,則依然以十進制對待該數(shù)字位,并忽略最高位的0,由于172.08.9.2808并不是一個合法的八進制數(shù),所以依然按十進制對待并忽略最高位的0,即實際解析成172.8.9.28

    此外,當輸入的IP地址并不是以逗號分割的四位,ping命令依然能夠正常解析。分別ping 196.168.072,192.168,196時,實際被解析成了 196.168.0.072,196.0.0.168,0.0.0.192

    Java判斷ip是否為IPV4或IPV6地址的方式有哪些

    可以看出,當IP不足四位時,ping命令會在合適的位置補0,其規(guī)律如下所示:

    1 part  (ping A)       : 0.0.0.A
    2 parts (ping A.B)     : A.0.0.B
    3 parts (ping A.B.C)   : A.B.0.C
    4 parts (ping A.B.C.D) : A.B.C.D

    以上就是“Java判斷ip是否為IPV4或IPV6地址的方式有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

    AI