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

今天小编给大家分享一下Java判断ip是否为IPV4或IPV6地址的方式有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    判断字符串是否为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地址

        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即可实现快速的判断,但这个方式能同时判断字符串是否为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地址,它的正则表达式以及实现细节,其实和第一种方案中判断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类实现对IP的各项校验操作,结合该类的getByNamegetHostAddress方法可实现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长度的数字字符串组成,由于每位数字只有8bit长度,所以每个数字的值应该在0~255范围内。相关文档可以参考RFC5321。

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

    2. 有效性验证

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

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

    用例 isValidIPV4ByValidator isValidIPV6ByValidator isValidByGuava isValidIPV4ByOWASP isValidIPV4ByCustomRegex isValidIPV4ByJDK
    172.8.9.28 true false true true true true
    192.168.0.072 false false false true false false
    172.08.9.28 false false false true false false
    172.9.28 false false false false false false
    192.168.072 false false false false false false
    192.168.1 false false false false false false
    2001:0db8:85a3:0000:0000:8a2e:0370:7334 false true true false false false

    通过这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地址做输入,该方法的性能损耗将不敢想象!

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

        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实现的判断方法却用了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

    以上就是“Java判断ip是否为IPV4或IPV6地址的方式有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程之家行业资讯频道。

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

    相关推荐


    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
    今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
    Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&amp;FileOutputStream。
    作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
    本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
    Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = &quot;hello&quot;; 在代码中,我们
    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
    作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
    作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
    1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
    Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
    纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
    Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
    Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
    Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
    What is a programming language? Before introducing compilation and decompilation, let&#39;s briefly introduce the Programming Language. Programming la
    Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
    Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越