• IP地址工具 ——JAVA实现


    工具类中包含以下方法:

    1. 根据掩码统计网段可分配ip地址数(包含网络地址及广播地址)
    2. 根据网段地址和掩码计算有效ip地址范围(不包含网络地址和广播地址)
    3. 校验ip地址是否在目标网段范围内(不包含网络地址和广播地址)
    4. 根据网段和掩码计算范围极值
    5. 区间范围校验方法
    6. 多网段重叠校验,返回第一次出现重叠的两个网段

    包含前后端交互的数据结构 IpAddressRange

    简要描述下,大多对于ip地址的范围等计算都是对四个分段遍历循环进行的;
    多网段重叠校验,计算每个ip的极大值和极小值,把每个ip地址的极值计算成为一个数值,计算方法:a.b.c.d

    a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d

    用一个map,记录每个ip的极值坐标,key=极小值,value=极大值。把所有数值放入集合中从小到大排列后进行遍历,用一个指针指向当前遍历指针对应map里key对应的极大值,当前遍历指向的数值与指针指向的值不相等时则说明出现重叠,相等时则清空指针的指向的值,等待指向下一个极小值对应的极大值,以此往后重复校验。

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.apache.commons.lang3.ObjectUtils;
    
    import java.math.BigDecimal;
    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.function.Function;
    
    /**
     * ip地址工具类
     */
    public class IpAddressUtils {
    
        /**
         * 分段位数
         */
        public final static int SEGMENT_DIGIT = 8;
    
        /**
         * 网段位数
         */
        public final static int CIDR_DIGIT = 32;
    
        /**
         * ip地址分割符-切割用
         */
        public final static String IP_ADDRESS_SPLIT = "\\.";
    
        /**
         * ip地址分割符-添加用
         */
        public final static String IP_ADDRESS_POINT = ".";
        
        /**
         * ip与掩码间的分割符
         */
        public final static String IP_MASK_SPLIT = "/";
    
        /**
         * IP地址正则表达式
         */
        public static final String IP_DNS_RULE =
                "((?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d))))";
    
        /**
         * 根据掩码统计网段可分配ip地址数(包含网络地址及广播地址)
         *
         * @param mask 掩码:如 24
         * @return
         */
        public static Double countHostIpAddress(int mask) {
            int hostNum = CIDR_DIGIT - mask;
            return Math.pow(2, hostNum);
    
        }
    
    
        /**
         * 根据网段地址和掩码计算有效ip地址范围(不包含网络地址和广播地址)
         *
         * @param destination
         * @param mask
         * @return
         */
        public static List<IpAddressRange> calculateIpAddressRange(String destination, int mask) {
    
            ArrayList<IpAddressRange> ipAddressRanges = new ArrayList<>();
    
            String[] segments = destination.split(IP_ADDRESS_SPLIT);
    
            int integerNetworkNum = mask / SEGMENT_DIGIT;
    
            int tailNetworkNum = mask % SEGMENT_DIGIT;
    
            for (int i = 1; i <= segments.length; i++) {
                Integer defaultValue = Integer.valueOf(segments[i - 1]);
                if (i <= integerNetworkNum) {
                    ipAddressRanges.add(IpAddressRange.builder()
                            .position(i)
                            .disabled(Boolean.TRUE)
                            .defaultValue(defaultValue)
                            .build());
                } else {
                    // 范围最大值计算
                    Double rangeMaxValue;
                    if (i == integerNetworkNum + 1) {
                        rangeMaxValue = Math.pow(2, SEGMENT_DIGIT - tailNetworkNum) - 1 + defaultValue;
                    } else {
                        rangeMaxValue = Math.pow(2, SEGMENT_DIGIT) - 1 + defaultValue;
                    }
                    ipAddressRanges.add(IpAddressRange.builder()
                            .position(i)
                            .disabled(Boolean.FALSE)
                            .defaultValue(defaultValue)
                            .range(IpAddressRange.Range.builder()
                                    .rangeMinimum(defaultValue)
                                    .rangeMaximum(rangeMaxValue.intValue())
                                    .rangeStep(1)
                                    .build())
                            .build());
    
                }
    
            }
    
            return ipAddressRanges;
    
        }
    
        /**
         * 校验ip地址是否在目标网段范围内(不包含网络地址和广播地址)
         *
         * @param ipAddress
         * @param destination
         * @param mask
         * @return
         */
        public static boolean validIpAddress(String ipAddress, String destination, int mask) {
            // 先根据网段和掩码算出可用ip范围
            List<IpAddressRange> ipAddressRanges
                    = calculateIpAddressRange(destination, mask);
            String[] ipSegments = ipAddress.split(IP_ADDRESS_SPLIT);
            
            for (int i = 0; i < ipSegments.length; i++) {
                IpAddressRange ipAddressRange = ipAddressRanges.get(i);
                Integer ipSegment = Integer.valueOf(ipSegments[i]);
                // 不可编辑时说明是固定值,判断是否与固定值相等
                if (ipAddressRange.getDisabled() && !ipSegment.equals(ipAddressRange.getDefaultValue())) {
                    return false;
                }
                IpAddressRange.Range range = ipAddressRange.getRange();
                // 可编辑时范围区间判断
                if (!ipAddressRange.getDisabled() && ObjectUtils.isNotEmpty(range)) {
                    // 非末位段时,判断是否不在区间范围值内
                    if (!intervalValid(ipSegment, range.rangeMinimum, true, range.rangeMaximum, true)) {
                        return false;
                    }
                }
            }
            return true;
        }
    
        /**
         * 根据网段和掩码计算范围极值
         *
         * @param destination
         * @param mask
         * @param isMax
         * @return
         */
        public static String extremumCalculate(String destination, int mask, boolean isMax) {
            List<IpAddressRange> ipAddressRanges = calculateIpAddressRange(destination, mask);
    
            return isMax ?
                    extremumCalculateInner(ipAddressRanges, IpAddressRange.Range::getExtremumMax, IpAddressRange.Range::getRangeMaximum)
                    : extremumCalculateInner(ipAddressRanges, IpAddressRange.Range::getExtremumMin, IpAddressRange.Range::getRangeMinimum);
        }
    
        /**
         * 范围极值内部实现
         *
         * @param ipAddressRanges
         * @param extremum
         * @param rangeMum
         * @return
         */
        protected static String extremumCalculateInner(List<IpAddressRange> ipAddressRanges
                , Function<IpAddressRange.Range, Integer> extremum
                , Function<IpAddressRange.Range, Integer> rangeMum) {
    
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < ipAddressRanges.size(); i++) {
                IpAddressRange ipAddressRange = ipAddressRanges.get(i);
                if (ipAddressRange.getDisabled()) {
                    result.append(ipAddressRange.getDefaultValue());
                } else {
                    IpAddressRange.Range range = ipAddressRange.getRange();
                    if (null != range.getExtremumMax()) {
                        result.append(extremum.apply(range));
                    } else {
                        result.append(rangeMum.apply(range));
                    }
                }
                if (i < (ipAddressRanges.size() - 1)) {
                    result.append(IP_ADDRESS_POINT);
                }
            }
            return result.toString();
        }
    
        /**
         * 区间范围校验
         *
         * @param target
         * @param left
         * @param includeLeft
         * @param right
         * @param includeRight
         * @return
         */
        public static boolean intervalValid(Integer target, Integer left, Boolean includeLeft, Integer right, Boolean includeRight) {
            if (includeLeft && target >= left) {
                if (includeRight && target <= right) {
                    return true;
                } else {
                    return !includeRight && target < right;
                }
            } else if (!includeLeft && target > left) {
                if (includeRight && target <= right) {
                    return true;
                } else {
                    return !includeRight && target < right;
                }
            }
            return false;
        }
    
        /**
         * 网段重叠校验
         * @param cidrList
         * @return 为null校验成功,否则返回第一次出现重叠的两个网段
         */
        public static String[] validCidrOverlap(List<Cidr> cidrList){
            // 记录每一个坐标对应的下一跳坐标
            HashMap<String, Map<String, Cidr>> rangeMaps = new HashMap<>();
            // 坐标轴(数值线)
            ArrayList<String> ipNumRangeLine = new ArrayList<>();
            // 每一个网段的范围极值作为一组坐标塞入rangeMaps和坐标轴
            cidrList.forEach(cidr -> {
                String maxIp = extremumCalculate(cidr.destination, cidr.mask, true);
                String minIp = extremumCalculate(cidr.destination, cidr.mask, false);
                String maxIpNum = calculateIpNum(maxIp).concat(IP_MASK_SPLIT).concat(String.valueOf(cidr.mask));
                String minIpNum = calculateIpNum(minIp).concat(IP_MASK_SPLIT).concat(String.valueOf(cidr.mask));
                ipNumRangeLine.add(maxIpNum);
                ipNumRangeLine.add(minIpNum);
                HashMap<String, Cidr> maxRangeMap = new HashMap<>(1);
                maxRangeMap.put(maxIpNum, cidr);
                rangeMaps.put(minIpNum, maxRangeMap);
            });
            // 将坐标轴上所有坐标按照数组坐标大小排序
            ipNumRangeLine.sort(Comparator.comparing(ipNum -> ipNum.split(IP_MASK_SPLIT)[0]));
            // 下一跳坐标的指针
            Map<String, Cidr> targetIpNumMap = null;
            for (int i = 0; i < ipNumRangeLine.size(); i++) {
                String ipNum = ipNumRangeLine.get(i);
                Map<String, Cidr> doubleCidrMap = rangeMaps.get(ipNum);
                if (null != targetIpNumMap){
                    // 如果下一跳坐标不是rangeMaps里绑定的最大值坐标说明范围出现重叠
                    if (null == targetIpNumMap.get(ipNum)){
                        String cidr1 = doubleCidrMap.values().stream().map(cidr -> cidr.destination.concat(IP_MASK_SPLIT).concat(String.valueOf(cidr.mask))).findFirst().get();
                        String cidr2 = targetIpNumMap.values().stream().map(cidr -> cidr.destination.concat(IP_MASK_SPLIT).concat(String.valueOf(cidr.mask))).findFirst().get();
                        return new String[]{cidr1, cidr2};
                    }else {
                        // 指针重新定位
                        targetIpNumMap = null;
                    }
                }else {
                    targetIpNumMap = doubleCidrMap;    
                }
            }
            return null;
        }
    
        private static String calculateIpNum(String maxIp) {
            String[] segments = maxIp.split(IP_ADDRESS_SPLIT);
            return BigDecimal.valueOf((long) Integer.parseInt(segments[0]) * ((Double)Math.pow(2, SEGMENT_DIGIT*3)).intValue())
                    .add(BigDecimal.valueOf((long) Integer.parseInt(segments[1]) * ((Double)Math.pow(2, SEGMENT_DIGIT*2)).intValue()))
                    .add(BigDecimal.valueOf((long) Integer.parseInt(segments[2]) * ((Double)Math.pow(2, SEGMENT_DIGIT)).intValue()))
                    .add(BigDecimal.valueOf((long) Integer.parseInt(segments[3]) * ((Double)Math.pow(2, 0)).intValue())).toString();
        }
    
        public static void main(String[] args) {
            ArrayList<Cidr> cidrs = new ArrayList<>();
            cidrs.add(new Cidr("192.168.0.0", 24));
            cidrs.add(new Cidr("192.168.128.32", 27));
            cidrs.add(new Cidr("192.168.128.0", 25));
            validCidrOverlap(cidrs);
        }
    
    
        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class Cidr {
            /**
             * 目标网段
             */
            private String destination;
    
            /**
             * 掩码
             */
            private Integer mask;
            
        }
    
    
        @Data
        @Builder
        @AllArgsConstructor
        @NoArgsConstructor
        public static class IpAddressRange {
            /**
             * ip位,1,2,3,4
             */
            private Integer position;
            /**
             * 当前位输入框是否禁用,true/false
             */
            private Boolean disabled;
            /**
             * 当前位默认值
             */
            private Integer defaultValue;
            /**
             * 输入框范围
             */
            private Range range;
    
    
            @Data
            @Builder
            @AllArgsConstructor
            @NoArgsConstructor
            public static class Range {
                /**
                 * 范围可取最小值
                 */
                private Integer rangeMinimum;
                /**
                 * 范围可取最大值
                 */
                private Integer rangeMaximum;
                /**
                 * 范围极大值(用于末段位范围,如果前面的取值都是最大值,末段位范围的最大值应取该值)
                 */
                private Integer extremumMax;
                /**
                 * 范围极小值(用于末段位范围,如果前面的取值都是最小值,末段位范围的最小值应取该值)
                 */
                private Integer extremumMin;
                /**
                 * 范围间隔(步频/公差……)
                 */
                private Integer rangeStep;
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
  • 相关阅读:
    java计算机毕业设计课堂互动应答系统mp4源码+mysql数据库+系统+lw文档+部署
    Amazon 消息订阅对接
    设计模式之观察者模式
    [b01lers2020]Life on Mars (难发现的sql注入)
    UE5 虚幻引擎,打开空间蓝图,出现未识别的选项卡
    python 虚拟环境搭建
    解决 Ajax:Ensure CORS response header values are valid 跨域问题
    案例赏析 | 土耳其开赛利:闲置屋顶坐享“阳光收益”,助力企业实现绿色低碳转型
    Vue2项目练手——通用后台管理项目第四节
    UOS设备管理器中的信息获取(无须提权)
  • 原文地址:https://blog.csdn.net/weixin_45365220/article/details/127726356