是否存在用于在Java中存储IP地址的特定数据类型?我有一个特定的功能要求:
我知道java.net.inetaddress
,但我相信它并没有给我这个功能。有什么想法吗?
答案 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的一个缺点是getByName
会导致DNS访问。如果您想避免对DNS进行惩罚,您可能需要查看Guava的com.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