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

时间:2011-12-30 08:45:37

标签: java ip

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

  1. 给定IP范围和IP,如果它在其中,则返回true,否则返回false。 例如:范围10.10.10.1-10.10.11.255和IP 10.10.10.192应返回true。
  2. 我知道java.net.inetaddress,但我相信它并没有给我这个功能。有什么想法吗?

7 个答案:

答案 0 :(得分:13)

IP(IPv4)是32位(与Java中的int相同)。由于您希望使用无符号整数进行比较(如果您需要支持IP高于128.0.0.0),则需要使用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

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

答案 1 :(得分:13)

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

  • 使用显式类型InetAddress而不是long来维护和调试更容易:您的调试器实际上将显示“10.10.10.1”而不是“168430081”
  • IPv6既不是问题,也可以在没有太多额外麻烦的情况下实施。

InetAddress的一个缺点是getByName会导致DNS访问。如果您想避免对DNS进行惩罚,您可能需要查看Guavacom.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 :(得分:3)

对于IPv4,我会使用int值。将IP地址转换为数字,您可以使用数字操作。

如果你想进行范围超过127.x.x.x(环回lan)到128.x.x.x的比较,这是不太可能的,但是你可以这样做,你可以翻转顶部位,范围比较仍然有用。

使用@ user1的示例。检查210.210.210.192是否介于210.210.210.1和210.210.211.255

之间
210.210.210.1 is: (210 << 24) + (210 << 16) + (210 << 8) + 1 = -757935615
210.210.211.255 is: (210 << 24) + (210 << 16) + (211 << 8) + 255 = -757935105

210.210.210.192 is: (210 << 24) + (210 << 16) + (210 << 8) + 192 = -757935424

最后一个IP地址在范围内,因为-757935615&lt; = -757935424&amp;&amp; -757935424&lt; = -757935105

答案 3 :(得分:3)

如果您的IP地址范围可以在公共CIDR format中表示,则可以使用Apache Common's SubnetUtils

SubnetUtils.SubnetInfo subnet = new SubnetUtils("192.168.0.3/31");
return subnet.isInRange(testIpAddress);

答案 4 :(得分:2)

将IP地址转换为长整数。 有关同一问题的详细讨论,请参阅Given a list of IP address, how do you find min, max?

答案 5 :(得分:2)

试试这个:

import static org.junit.Assert.*;
import org.junit.Test;
import java.math.BigInteger;
import java.net.*;
class IpRange {
    IpRange(InetAddress from, InetAddress to) {
        if(!from.getClass().equals(to.getClass())) throw new RuntimeException("different versions of ip address!");
        this.from = new BigInteger(from.getAddress());
        this.to = new BigInteger(to.getAddress());
    }
    boolean isInRange(InetAddress inetAddress) {
        BigInteger bigInteger = new BigInteger(inetAddress.getAddress());
        return !(from.compareTo(bigInteger) == 1 || bigInteger.compareTo(to) == 1);
    }
    final BigInteger from, to;
}
public class IpRangeTestCase {
    @Test public void testInRange() throws UnknownHostException {
        InetAddress from = InetAddress.getByAddress(new byte[] { 10, 10, 10, 1 });
        InetAddress x = InetAddress.getByAddress(new byte[] { 10, 10, 10, 42 });
        InetAddress to = InetAddress.getByAddress(new byte[] { 10, 10, 10, (byte) 192 });
        IpRange ipRange = new IpRange(from, to);
        assertTrue(ipRange.isInRange(from));
        assertTrue(ipRange.isInRange(x));
        assertTrue(ipRange.isInRange(to));
        InetAddress toSmall = InetAddress.getByAddress(new byte[] { 10, 10, 9, 1 });
        assertFalse(ipRange.isInRange(toSmall));
        InetAddress toBig = InetAddress.getByAddress(new byte[] { 10, 10, 10, (byte) 193 });
        assertFalse(ipRange.isInRange(toBig));
        InetAddress fromv6=InetAddress.getByAddress(new byte[] {(byte)0xfe,(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,(byte)0xb3,(byte)0xff,(byte)0xfe,0x1e,(byte)0x83,0x20});
        InetAddress xv6=InetAddress.getByAddress(new byte[] {(byte)0xfe,(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,(byte)0xb3,(byte)0xff,(byte)0xfe,0x1e,(byte)0x83,0x29});
        InetAddress tov6=InetAddress.getByAddress(new byte[] {(byte)0xfe,(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,(byte)0xb3,(byte)0xff,(byte)0xfe,0x1e,(byte)0x83,0x40});
        IpRange ipRangev6 = new IpRange(fromv6, tov6);
        assertTrue(ipRangev6.isInRange(xv6));
    }
    @Test (expected=RuntimeException.class) public void testInRangeThrows() throws UnknownHostException {
        InetAddress v4 = InetAddress.getByAddress(new byte[] { 10, 10, 10, 1 });
        InetAddress v6=InetAddress.getByAddress(new byte[] {(byte)0xfe,(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,(byte)0xb3,(byte)0xff,(byte)0xfe,0x1e,(byte)0x83,0x29});
        new IpRange(v4, v6);
    }
}

答案 6 :(得分:0)

只需使用java的原始long