欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java判斷ip是否為IPV4或IPV6地址的多種方式

 更新時(shí)間:2023年03月02日 10:21:55   作者:Alphathur  
本文主要介紹了Java判斷ip是否為IPV4或IPV6地址的多種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

判斷字符串是否為IP地址通常都是基于正則表達(dá)式實(shí)現(xiàn)的,無論是引入外部的依賴包亦或是自己寫正則實(shí)現(xiàn),基本都是基于正則表達(dá)式實(shí)現(xiàn)的判斷。然而比較例外的是,jdk自身提供了Inet4Address.getByName方法也可以幫助我們實(shí)現(xiàn)ip地址的判斷。本文將詳細(xì)列舉常見的判斷字符串是否為IPV4,IPV6地址的方式,并分析其存在的局限性。

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

1. 使用Apache Commons Validator做判斷

需要引入依賴包

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

有了依賴包,后續(xù)調(diào)用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>

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

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

3. 使用OWASP正則表達(dá)式做判斷

OWASP提供了一系列用于校驗(yàn)常見web應(yīng)用名詞的正則表達(dá)式,通過OWASP_Validation_Regex_Repository你可以檢索到他們。這個(gè)判斷方式只能判斷是否為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. 使用自定義正則表達(dá)式做判斷

如下通過自定義的正則表達(dá)式判斷字符串是否為IPV4地址,它的正則表達(dá)式以及實(shí)現(xiàn)細(xì)節(jié),其實(shí)和第一種方案中判斷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內(nèi)置的Inet4Address做判斷

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

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

二、并不適合ping命令

1. IPV4的標(biāo)準(zhǔn)格式

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

在這里插入圖片描述

2. 有效性驗(yàn)證

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

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

用例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個(gè)測(cè)試用例中,不難看出:

  • 第1個(gè)IP剛好是4位,每位都在0~255之間,且沒有任何一位以0開頭。所有判斷IPV4的方法都返回了true,符合預(yù)期。
  • 第2,3個(gè)IP也都是4位地址,但是某一位出現(xiàn)以0開始的數(shù)字,此時(shí)采用OWASP正則表達(dá)式的方式返回了true,其他方法都返回了false。
  • 第4,5,6個(gè)IP都是3位地址,所有方法返回了false。
  • 最后一個(gè)是合法的ipv6地址,我們通過Apache Commons Validator或者Guava包提供的判斷方法能夠正常返回true。

3. 性能對(duì)比

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

下面將通過一項(xiàng)測(cè)試來驗(yàn)證這個(gè)結(jié)論。

    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方法來產(chǎn)生一批隨機(jī)的IP地址,這些IP中有正確格式的,也有非法格式的。

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

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

直接運(yùn)行后,打印以下結(jié)果。

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

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

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

對(duì)于標(biāo)準(zhǔn)IPV4格式的地址來說,以上判斷方式是沒問題的,但是部分非標(biāo)準(zhǔn)IPV4格式的地址,卻能夠被ping命令正常解析。

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

不妨驗(yàn)證一下:

在這里插入圖片描述

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

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

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

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

在這里插入圖片描述

可以看出,當(dāng)IP不足四位時(shí),ping命令會(huì)在合適的位置補(bǔ)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

三、小結(jié)

這幾種判斷字符串是否為IPV4或者IPV6地址的方式,其內(nèi)在實(shí)現(xiàn)原理都大同小異,除了最后一個(gè)方案外都是用正則表達(dá)式來實(shí)現(xiàn)的。

但是基于正則表達(dá)式實(shí)現(xiàn)的方法并不能很友好地處理非十進(jìn)制數(shù)字位的情況,而ping命令能夠接收的字符串遠(yuǎn)比這個(gè)復(fù)雜的多,如果你想通過Java來實(shí)現(xiàn)判斷ping命令后面的地址是否是合法的IP,那應(yīng)該是難于上青天,除非你去弄懂ping命令的底層源碼。

當(dāng)然在現(xiàn)實(shí)業(yè)務(wù)場(chǎng)景中,我們判斷字符串是否為合法IP地址一般都是基于其標(biāo)準(zhǔn)格式來操作的,也不用擔(dān)心文中的方法不靠譜,除了第3和最后一個(gè)方案外,大膽用吧!

到此這篇關(guān)于Java判斷ip是否為IPV4或IPV6地址的多種方式的文章就介紹到這了,更多相關(guān)Java判斷ip是否為IPV4或IPV6內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis加載映射文件和動(dòng)態(tài)代理的實(shí)現(xiàn)

    MyBatis加載映射文件和動(dòng)態(tài)代理的實(shí)現(xiàn)

    本文主要介紹了MyBatis加載映射文件和動(dòng)態(tài)代理的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Java 內(nèi)省introspector相關(guān)原理代碼解析

    Java 內(nèi)省introspector相關(guān)原理代碼解析

    這篇文章主要介紹了Java 內(nèi)省introspector相關(guān)原理代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • springbooot使用google驗(yàn)證碼的功能實(shí)現(xiàn)

    springbooot使用google驗(yàn)證碼的功能實(shí)現(xiàn)

    這篇文章主要介紹了springbooot使用google驗(yàn)證碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • SpringBoot+Vue靜態(tài)資源刷新后無法訪問的問題解決方案

    SpringBoot+Vue靜態(tài)資源刷新后無法訪問的問題解決方案

    這篇文章主要介紹了SpringBoot+Vue靜態(tài)資源刷新后無法訪問的問題解決方案,文中通過代碼示例和圖文講解的非常詳細(xì),對(duì)大家解決問題有一定的幫助,需要的朋友可以參考下
    2024-05-05
  • 國(guó)內(nèi)分布式框架Dubbo使用詳解

    國(guó)內(nèi)分布式框架Dubbo使用詳解

    這篇文章主要為大家介紹了國(guó)內(nèi)分布式框架Dubbo使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 在Spring中配置Quartz的三種方式

    在Spring中配置Quartz的三種方式

    Spring Quartz 是一個(gè)任務(wù)調(diào)度框架,它允許我們定期執(zhí)行特定的任務(wù),在 Spring 中,我們可以通過多種方式來配置 Quartz,包括使用 ??@Scheduled?? 注解、XML 配置和 Java 配置,本文將介紹如何在 Spring 中使用這三種方式來配置 Quartz,需要的朋友可以參考下
    2025-01-01
  • Springboot通過ObjectMapper配置json序列化詳解

    Springboot通過ObjectMapper配置json序列化詳解

    SpringBoot默認(rèn)集成Jackson庫,其中ObjectMapper類是核心,用于Java對(duì)象與JSON字符串的互轉(zhuǎn),提供配置序列化特性、注冊(cè)模塊等方法,在SpringBoot中可以全局配置JSON格式,如日期格式化、將Long轉(zhuǎn)為字符串,還可以配置序列化時(shí)的各種規(guī)則,感興趣的可以了解一下
    2024-10-10
  • @CacheEvict注解,清除緩存方式

    @CacheEvict注解,清除緩存方式

    這篇文章主要介紹了@CacheEvict注解,清除緩存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Spring?boot事務(wù)無效報(bào)錯(cuò):Transaction?not?enabled問題排查解決

    Spring?boot事務(wù)無效報(bào)錯(cuò):Transaction?not?enabled問題排查解決

    在業(yè)務(wù)代碼中經(jīng)常需要保證事務(wù)的原子性,但是有的時(shí)候確實(shí)是出現(xiàn)事務(wù)沒有生效,這篇文章主要給大家介紹了關(guān)于Spring?boot事務(wù)無效報(bào)錯(cuò):Transaction?not?enabled問題排查的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 解決Springboot項(xiàng)目中很多頁面出現(xiàn)Whitelabel Error Page(404)的問題

    解決Springboot項(xiàng)目中很多頁面出現(xiàn)Whitelabel Error Page(404)的問題

    最近在接手的前后端項(xiàng)目中發(fā)現(xiàn)其默認(rèn)路徑不是主機(jī)+端口(如:http://localhost:3453/)的形式,很多頁面的訪問是加了一個(gè)層級(jí),只要訪問頁面就會(huì)出現(xiàn)Whitelabel Error Page(404),所以本文給大家提供了解決方案,需要的朋友可以參考下
    2024-02-02

最新評(píng)論