Java判断ip是否为IPV4或IPV6地址的方式有哪些(IP,java,开发技术)

时间:2024-04-28 03:35:07 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    判断字符串是否为IP地址通常都是基于正则表达式实现的,无论是引入外部的依赖包亦或是自己写正则实现,基本都是基于正则表达式实现的判断。然而比较例外的是,jdk自身提供了Inet4Address.getByName方法也可以帮助我们实现ip地址的判断。

    一、判断是否为IPV4,IPV6地址的常见方式

    1. 使用Apache Commons Validator做判断

    需要引入依赖包

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

    有了依赖包,后续调用InetAddressValidator的核心API就好了。

    1.1判断是否为IPV4地址

    privatestaticfinalInetAddressValidatorVALIDATOR=InetAddressValidator.getInstance();publicstaticbooleanisValidIPV4ByValidator(StringinetAddress){returnVALIDATOR.isValidInet4Address(inetAddress);}

    1.2判断是否为IPV6地址

    publicstaticbooleanisValidIPV6ByValidator(StringinetAddress){returnVALIDATOR.isValidInet6Address(inetAddress);}

    1.3判断是否为IPV6或者IPV4地址

    publicstaticbooleanisValidIPV6ByValidator(StringinetAddress){returnVALIDATOR.isValid(inetAddress);}

    2. 使用Guava做判断

    引入依赖包

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

    调用InetAddresses.isInetAddress即可实现快速的判断,但这个方式能同时判断字符串是否为IPV4或者IPV6地址,如果你只想判断其中一种格式,那就不行了。

    publicstaticbooleanisValidByGuava(Stringip){returnInetAddresses.isInetAddress(ip);}

    3. 使用OWASP正则表达式做判断

    OWASP提供了一系列用于校验常见web应用名词的正则表达式,通过OWASP_Validation_Regex_Repository你可以检索到他们。这个判断方式只能判断是否为IPV4地址。

    privatestaticfinalStringOWASP_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]?)$";privatestaticfinalPatternOWASP_IPv4_PATTERN=Pattern.compile(OWASP_IPV4_REGEX);publicstaticbooleanisValidIPV4ByOWASP(Stringip){if(ip==null||ip.trim().isEmpty()){returnfalse;}returnOWASP_IPv4_PATTERN.matcher(ip).matches();}

    4. 使用自定义正则表达式做判断

    如下通过自定义的正则表达式判断字符串是否为IPV4地址,它的正则表达式以及实现细节,其实和第一种方案中判断IPV4是一致的,如果你只想判断字符串是否为IPV4地址,又懒得引入外部包,那么3,4这两种方式适合你。

    privatestaticfinalStringIPV4_REGEX="^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$";privatestaticfinalPatternIPv4_PATTERN=Pattern.compile(IPV4_REGEX);publicstaticbooleanisValidIPV4ByCustomRegex(Stringip){if(ip==null||ip.trim().isEmpty()){returnfalse;}if(!IPv4_PATTERN.matcher(ip).matches()){returnfalse;}String[]parts=ip.split("\\.");try{for(Stringsegment:parts){if(Integer.parseInt(segment)>255||(segment.length()>1&&segment.startsWith("0"))){returnfalse;}}}catch(NumberFormatExceptione){returnfalse;}returntrue;}

    5. 使用JDK内置的Inet4Address做判断

    JDK从1.4版本开始就提供了Inet4Address类实现对IP的各项校验操作,结合该类的getByNamegetHostAddress方法可实现IP地址判断,但是频繁的调用这两个方法会产生一定的性能问题。以下是通过JDK判断字符串是否为IPV4地址的方式:

    publicstaticbooleanisValidIPV4ByJDK(Stringip){try{returnInet4Address.getByName(ip).getHostAddress().equals(ip);}catch(UnknownHostExceptionex){returnfalse;}}

    二、并不适合ping命令

    1. IPV4的标准格式

    本文列举的几种判断方式都是针对标准的IP地址而言,标准指的是IP地址由4位通过逗号分割的8bit长度的数字字符串组成,由于每位数字只有8bit长度,所以每个数字的值应该在0~255范围内。相关文档可以参考RFC5321。

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

    2. 有效性验证

    我们选举几组字符串,有缺少位数的,有数字以0开头的,也有一组是符合标准格式的。然后通过之前列举的方法判断是否为有效的IP地址。

    测试过程就不再赘述,直接将测试用例和测试结果汇总成如下的表格:

    用例isValidIPV4ByValidatorisValidIPV6ByValidatorisValidByGuavaisValidIPV4ByOWASPisValidIPV4ByCustomRegexisValidIPV4ByJDK172.8.9.28truefalsetruetruetruetrue192.168.0.072falsefalsefalsetruefalsefalse172.08.9.28falsefalsefalsetruefalsefalse172.9.28falsefalsefalsefalsefalsefalse192.168.072falsefalsefalsefalsefalsefalse192.168.1falsefalsefalsefalsefalsefalse2001:0db8:85a3:0000:0000:8a2e:0370:7334falsetruetruefalsefalsefalse

    通过这7个测试用例中,不难看出:

    • 第1个IP刚好是4位,每位都在0~255之间,且没有任何一位以0开头。所有判断IPV4的方法都返回了true,符合预期。

    • 第2,3个IP也都是4位地址,但是某一位出现以0开始的数字,此时采用OWASP正则表达式的方式返回了true,其他方法都返回了false。

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

    • 最后一个是合法的ipv6地址,我们通过Apache Commons Validator或者Guava包提供的判断方法能够正常返回true。

    3. 性能对比

    本文在列举的第5个判断方法时特意提到了性能问题,那么使用Inet4Address判断IP地址到底会导致多大的性能损耗呢?实验证明,当判断使用大规模非法IP地址做输入,该方法的性能损耗将不敢想象!

    下面将通过一项测试来验证这个结论。

    privatestaticList<String>generateFakeIp(intcapacity){List<String>ipList=newArrayList<String>(capacity);for(inti=0;i<capacity;i++){intparts=boundRandom(1,3);if(chanceOf50()){//eachiphas50%chancetobe4partsparts=4;}StringBuildersbBuilder=newStringBuilder();for(intj=0;j<parts;j++){if(sbBuilder.length()>0){sbBuilder.append(".");}StringBuilderstringBuilder=newStringBuilder();if(chanceOf10()){//eachparthas10%chancetogenerateafakenumberstringBuilder.append('a');}else{//eachparthas90%chancetogeneratethecorrectnumberstringBuilder.append(boundRandom(0,255));}sbBuilder.append(stringBuilder);}ipList.add(sbBuilder.toString());}returnipList;}privatestaticlongcorrectCount(List<String>ipList){returnipList.stream().filter(ip->isValidIPV4ByCustomRegex(ip)).collect(Collectors.toList()).size();}//50%chanceprivatestaticbooleanchanceOf50(){returnboundRandom(0,9)<5;}//10%chanceprivatestaticbooleanchanceOf10(){returnboundRandom(0,9)<1;}privatestaticRandomrandom=newRandom();//randomintbetween[start,end],bothstartandendareincludedprivatestaticintboundRandom(intstart,intend){returnstart+random.nextInt(end);}

    我们通过上面的generateFakeIp方法来产生一批随机的IP地址,这些IP中有正确格式的,也有非法格式的。

    主体测试方法如下,该方法将比较isValidIPV4ByCustomRegexisValidIPV4ByJDK这两种判断IP地址的总耗时,以分析性能问题。

    publicstaticvoidperformanceTest(){List<String>ipList=generateFakeIp(100);doublechance=correctCount(ipList);System.out.println("starttesting,correctipcountis:"+chance);longt1=System.currentTimeMillis();ipList.stream().forEach(ip->isValidIPV4ByCustomRegex(ip));longt2=System.currentTimeMillis();ipList.stream().forEach(ip->isValidIPV4ByJDK(ip));longt3=System.currentTimeMillis();System.out.println("isValidIPV4ByCustomRegexcosttime:"+(t2-t1));System.out.println("isValidIPV4ByJDKcosttime:"+(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实现的判断方法却用了13s,这已经不在在同一个数量级了。如果我们将测试基数再扩大,那更加不敢想象,所以实际工作中,千万不要使用Inet4Address来做IP合法性判断。

    4. 判断IPV4的方法并不适合ping命令

    对于标准IPV4格式的地址来说,以上判断方式是没问题的,但是部分非标准IPV4格式的地址,却能够被ping命令正常解析。

    对于ping命令来说,我们这里列举的第2~6个IP地址都是合法的,能够被正常解析。

    不妨验证一下:

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

    可以看出,当我们输入的IP地址中,某一位数字位以0开头,那么也能被正常解析,从图片可以看出192.168.0.072被解析成了192.168.0.58172.08.9.28被解析成了172.08.9.28。这是为什么呢?

    当ping命令接收的IP地址中,出现以0开头的数字位,那么ping命令将尝试以八进制解析该位,八进制的072,即对应十进制的58,所以192.168.0.072就被解析成了192.168.0.58

    如果以0开头的数字位,不符合八进制的格式,则依然以十进制对待该数字位,并忽略最高位的0,由于172.08.9.2808并不是一个合法的八进制数,所以依然按十进制对待并忽略最高位的0,即实际解析成172.8.9.28

    此外,当输入的IP地址并不是以逗号分割的四位,ping命令依然能够正常解析。分别ping 196.168.072192.168196时,实际被解析成了 196.168.0.072196.0.0.1680.0.0.192

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

    可以看出,当IP不足四位时,ping命令会在合适的位置补0,其规律如下所示:

    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

     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:Java判断ip是否为IPV4或IPV6地址的方式有哪些的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:Java调度线程池ScheduledThreadPoolExecutor不执行问题怎么解决下一篇:

    7 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18