IPv4/IPv6地址范围与网络地址/子网掩码的转换,点分十进制与数字掩码的转换

private static final int IPV4BYTES = 4; // IPv4字节数为4
private static final int BYTEBITS = 8; // 每个字节的比特位长度为8

/* IPv4,计算一个地址范围所属最小"网络地址/子网掩码"
    例:1.1.0.1-1.1.3.10或者1.1.3.10-1.1.0.1
    1.1.0.1: 00000001 00000001 00000001 00000001
    1.1.3.10:00000001 00000001 00000011 00001010
    从左至右找到第一个不同所在位置,得到子网掩码为22
    将子网掩码后面的位数置为0,得到网络地址1.1.0.0
    返回1.1.0.0/22
  */
public static String getNetworkAddressAndNumMask(String startAddress, String endAddress) {
    String networkAddress = "";
    int mask = 0;

    // 用.分隔起始地址和结束地址,并将String型数组转为int型数组
    String[] startStrArr = startAddress.split("\\.");
    int[] startNums = Arrays.asList(startStrArr).stream().mapToInt(Integer::parseInt).toArray();
    String[] endStrArr = endAddress.split("\\.");
    int[] endNums = Arrays.asList(endStrArr).stream().mapToInt(Integer::parseInt).toArray();

    // 计算子网掩码
    for (int i = 0; i < IPV4BYTES; i++) {
        int xorValue = startNums[i] ^ endNums[i]; // 异或操作
        if (xorValue > 0) {
            for (int j = 1; j <= BYTEBITS; j++) {
                if ((xorValue >>> j) == 0) { // 右移直至为0
                    mask += (BYTEBITS - j); // 8减右移位数为网络位
                    break;
                }
            }
            break;
        } else { // 如果异或值为0,则目前的8位为网络位
            mask += BYTEBITS;
        }
    }

    // 计算网络地址
    int[] networkNums = new int[IPV4BYTES];
    for (int i = 0; i < IPV4BYTES; i++) {
        if (mask / BYTEBITS > i) {
            networkNums[i] = startNums[i];
        } else if (mask / BYTEBITS == i) {
            networkNums[i] = startNums[i] & (255 << (BYTEBITS - mask % BYTEBITS));
        } else {
            networkNums[i] = 0;
        }
    }
    networkAddress = StringUtils.join(networkNums, ".");

    return networkAddress + "/" + mask;
}

/* IPv4,计算一个地址范围所属最小"网络地址 点分十进制掩码"
    例:1.1.0.1-1.1.3.10返回1.1.0.0 255.255.252.0
  */
public static String getNetworkAddressAndDottedDecimalMask(String startAddress, String endAddress) {
    String networkMask = getNetworkAddressAndNumMask(startAddress, endAddress);
    String networkAddress = networkMask.split("/")[0]; // 网络地址
    int numMask = Integer.parseInt(networkMask.split("/")[1]); // 子网掩码,数字

    String dottedDecimalMask = numMaskToDottedDecimalMask(numMask); // 子网掩码,点分十进制

    return networkAddress + " " + dottedDecimalMask;
}

// IPv4,将子网掩码数字转为点分十进制
public static String numMaskToDottedDecimalMask(int numMask) {
    int[] networkNums = new int[IPV4BYTES];

    for (int i = 0; i < IPV4BYTES; i++) {
        if (numMask / BYTEBITS > i) {
            networkNums[i] = 255;
        } else if (numMask / BYTEBITS == i) {
            networkNums[i] = (255 << (BYTEBITS - numMask % BYTEBITS)) & 255;
        } else {
            networkNums[i] = 0;
        }
    }

    return StringUtils.join(networkNums, ".");
}

// IPv4,将子网掩码点分十进制转为数字
public static int dottedDecimalMaskToNumMask(String dottedDecimalMask) {
    int numMask = 0;

    String[] maskStr = dottedDecimalMask.split("\\.");
    int[] maskInt = Arrays.asList(maskStr).stream().mapToInt(Integer::parseInt).toArray();

    for (int i = 0; i < IPV4BYTES && maskInt[i] > 0; i++) {
        for (int j = 1; j <= BYTEBITS; j++) {
            if ((maskInt[i] << j & 255) == 0) { // 左移,直至遇到0
                numMask += j;
                break;
            }
        }
    }

    return numMask;
}

/* IPv6,计算一个地址范围所属最小"网络地址/前缀长度"
   例:1a::0-1a::ffff
   将IPv6地址转为全写
   从左至右找到第一个不同位所在位置,得到前缀长度
   将前缀长度后面的位数置为0,得到网络地址
 */
public static String getIPv6NetworkAddressAndPrefixLength(String startAddress, String endAddress) {
    String networkAddress = "";
    int prefixLen = 0;

    // 将起始结束地址转为IPv6全写格式
    // parseFullIPv6函数https://blog.csdn.net/yaocong1993/article/details/108727948
    startAddress = parseFullIPv6(startAddress);
    endAddress = parseFullIPv6(endAddress);

    // 用:分隔起始地址和结束地址,并将16进制String型数组转为10进制int型数组
    String[] startStrArr = startAddress.split(":");
    int[] startNums = new int[8];
    for (int i = 0; i < startStrArr.length; i++) {
        startNums[i] = Integer.parseInt(startStrArr[i], 16);
    }

    String[] endStrArr = endAddress.split(":");
    int[] endNums = new int[8];
    for (int i = 0; i < endStrArr.length; i++) {
        endNums[i] = Integer.parseInt(endStrArr[i], 16);
    }

    // 计算前缀长度
    for (int i = 0; i < 8; i++) {
        int xorValue = startNums[i] ^ endNums[i]; // 异或操作
        if (xorValue > 0) {
            for (int j = 1; j <= 16; j++) {
                if ((xorValue >>> j) == 0) { // 右移直至为0
                    prefixLen += (16 - j); // 16减右移位数为网络位
                    break;
                }
            }
            break;
        } else { // 如果异或值为0,则目前的16位为网络位
            prefixLen += 16;
        }
    }

    // 计算网络地址
    String[] networkStrArr = new String[8];
    for (int i = 0; i < 8; i++) {
        if (prefixLen / 16 > i) {
            networkStrArr[i] = startStrArr[i];
        } else if (prefixLen / 16 == i) {
            networkStrArr[i] = Integer.toHexString(startNums[i] & (65535 << (16 - prefixLen % 16)));
        } else {
            networkStrArr[i] = "0";
        }
    }
    networkAddress = StringUtils.join(networkStrArr, ":");

    return networkAddress + "/" + prefixLen;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值