用于存储 IP 地址的数据类型

2022-09-05 00:30:47

是否有用于在 Java 中存储 IP 地址的特定数据类型?我有一个特定的功能要求:

  1. 给定一个 IP 范围和一个 IP,如果它属于该范围,则返回 true,否则返回 false。例如:范围 10.10.10.1-10.10.11.255 和 IP 10.10.10.192 应返回 true。

我知道,但我相信它不会给我这个功能。有什么想法吗?java.net.inetaddress


答案 1

我会使用或其子类之一,并编写一个自定义比较器和一个范围类:java.net.InetAddress

  • 使用显式类型 InetAddress 而不是仅 longs 更容易进行维护和调试:调试器实际上将显示“10.10.10.1”而不是“168430081”
  • IPv6要么没有问题,要么可以毫不费力地实现。

InetAddress的一个缺点是导致DNS访问。如果你想避免DNS的惩罚,你可能想看看番石榴的助手类。getByNamecom.google.common.net.InetAddresses

public enum InetAddressComparator implements Comparator<InetAddress> {

  INSTANCE;

  public int compare(InetAddress first, InetAddress second) {
    byte[] firstBytes = first.getAddress();
    byte[] secondBytes = second.getAddress();
    if (firstBytes.length != secondBytes.length) {
      throw new IllegalArgumentException("Cannot compare IPv4 and IPv6 addresses");
    }
    // getAddress returns bytes in network byte order:
    // the least significant byte is at the last index
    for (int i = firstBytes.length - 1; i >= 0; i--) {
      // translate the byte to an int with only the last 8 bits set,
      // effectively treating it as unsigned
      int a = firstBytes[i] & 0xff;
      int b = secondBytes[i] & 0xff;
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      }
    }
    return 0;
  }

}

public class Range<T> {

  private T lower;
  private T upper;
  private Comparator<T> comparator;

  public Range(T lower, T upper, Comparator<T> comparator) {
    if (comparator.compare(lower, upper) <= 0) {
      this.lower = lower;
      this.upper = upper;
    } else {
      this.lower = upper;
      this.upper = lower;
    }
    this.comparator = comparator;
  }

  public boolean contains(T element) {
    return comparator.compare(lower, element) <= 0 &&
      comparator.compare(upper, element) >= 0;
  }

}

public class Main {
  public static void main(String[] args) throws Exception {
    InetAddress start = InetAddress.getByName("10.10.10.1");
    InetAddress end = InetAddress.getByName("10.10.11.255");
    InetAddress test = InetAddress.getByName("10.10.10.192");
    assert InetAddressComparator.INSTANCE.compare(start, test) == -1;
    assert InetAddressComparator.INSTANCE.compare(end, test) == 1;
    assert InetAddressComparator.INSTANCE.compare(test, test) == 0;
    assert new Range<InetAddress>(start, end, InetAddressComparator.INSTANCE)
      .contains(test);
  }
}

答案 2

IP (IPv4) 为 32 位(与 Java 中的 int 大小相同)。由于您希望使用无符号整数进行比较(如果您需要支持高于 128.0.0.0 的 IP),因此您需要改用 long。

10.10.10.1 is: (10 << 24) + (10 << 16) + (10 << 8) + 1 = 168430081
10.10.11.255 is: (10 << 24) + (10 << 16) + (11 << 8) + 255 = 168430591

10.10.10.192 is: (10 << 24) + (10 << 16) + (10 << 8) + 192 = 168430272

由于 ,(换句话说168430272介于 168430081 和 168430272 之间),因此您的 IP 在范围内。168430081 <= 168430272 && 168430272 <= 168430591