将地址映射到唯一编号
Mapping Address to unique number
从 IP 地址生成唯一编号的最佳方法是什么?
19.22.145.103
我正计划对每个八位字节求和以获得唯一编号,但看起来我可能无法为每个 IP 地址获得唯一编号。
Sum of each octet 19 + 22 + 145 + 103 = 289 as the unique number.
我已经知道我们无法将 IPv4 映射到 16 位,因此可以接受冲突较少的解决方案。我正在寻找以下两点提到的解决方案。
- 首先,以 32 位数据类型存储唯一编号的最佳方法是什么?
- 其次,现在的问题是我需要将这个唯一编号存储在
short
数据类型中。由于 short 是 16 位,所以我们可能无法将 IPv4 唯一地映射到 short。如果我们仍然使用 short
数据类型而不是像我上面使用的那样使用每个八位位组的总和,我们是否还有其他方法可以减少冲突?
我所有的 IP 地址都以 10.
开头,如果有助于确定算法,那么冲突就会减少。
https://en.wikipedia.org/wiki/Hash_function
制作散列函数,然后将其切割成短的大小。例如:
(or some other prime numbers)
( 7 ^ 19 + 5 * 22 + 11 * 145 + 17 * 103 ) % size_of_short
你的任务通常是不可能的。所以我会从业务领域寻找捷径。
您需要映射所有个IP地址吗?您可以跳过 127.*.*.*
和 192.168.*.*
。但这还不够。你需要减少到 16 位,这是一个完整范围的摩擦:1 / 2^16
~ 1 / 64000
IPv4 是 4 个八位字节,因此您可以使用类似
的方式获得唯一的映射
public static int asInt(byte[] addr) {
return (addr[0] & 0xFF) | ((addr[1] & 0xFF) << 8)
| ((addr[2] & 0xFF) << 16) | ((addr[3] & 0xFF) << 24);
}
或
public static int asInt(byte[] addr) {
return ByteBuffer.wrap(addr).readInt();
}
这为您提供了 232 个可能的值。如果您想将其映射到 16 位并确保它是唯一的,您需要将映射存储在其他地方,例如
final Map<Integer, Short> mapping = new ConcurrentHashMap<>();
int next = 0;
public short idFor(byte[] bytes) {
Integer i = asInt(bytes);
return mapping.computeIfAbsent(i, x -> next++);
}
在 Java 7 你可以做
public short idFor(byte[] bytes) {
Integer i = asInt(bytes);
synchronized(mapping) {
Short s = mapping.get(i);
if (s == null)
mapping.put(i, s = next++);
return s;
}
}
注意,一个 16 位值只能有 65536 个可能的唯一值。
如果你想要一个简单的散列,你可以使用像
这样的东西
public short hash(int n) {
return (short) (n ^ (n >>> 16))
}
您可以添加聚合函数,例如
public short hash(int n) {
n *= 10191; // an odd prime of around 2^^16
return (short) (n ^ (n >>> 16))
}
不理想的是最高位不会以这种方式产生太多随机性。您可以改用 64 位计算。
public short hash(int n) {
long n2 = n * 0x6d0f27bdL;
n2 ^= (n2 >>> 21) ^ (n2 >>> 42);
return (short) (n ^ (n >>> 16) ^ (n >> 32));
}
我有一个新方法..检查代码,它保证您的代码是唯一的...
private static final int HASH_PRIME = 23;
public static short convertIP(String ip) {
String res = "";
for(String num: ip.split("\.")) {
int val = Integer.parseInt(num);
while(val>HASH_PRIME) {
val = val / HASH_PRIME;
}
if(new Random().nextInt(10) <= 4) {
res += convertChar(val);
} else {
res += val;
}
}
System.out.println("result = "+res); // the result could be anything like: T2264, 19WGE, TWGE, 1922G4, etc
return (short) (res.hashCode() % Short.MAX_VALUE);
}
private static char convertChar(int num) {
return (char)((num % 26) + 65);
}
public static void main(String[] args) {
System.out.println(convertIP("19.22.145.103"));
// the short code for the same IP will be unique majorly.. i.e. 24311, 23784, 31968, 16079, 23767 .. etc
}
从 IP 地址生成唯一编号的最佳方法是什么?
19.22.145.103
我正计划对每个八位字节求和以获得唯一编号,但看起来我可能无法为每个 IP 地址获得唯一编号。
Sum of each octet 19 + 22 + 145 + 103 = 289 as the unique number.
我已经知道我们无法将 IPv4 映射到 16 位,因此可以接受冲突较少的解决方案。我正在寻找以下两点提到的解决方案。
- 首先,以 32 位数据类型存储唯一编号的最佳方法是什么?
- 其次,现在的问题是我需要将这个唯一编号存储在
short
数据类型中。由于 short 是 16 位,所以我们可能无法将 IPv4 唯一地映射到 short。如果我们仍然使用short
数据类型而不是像我上面使用的那样使用每个八位位组的总和,我们是否还有其他方法可以减少冲突?
我所有的 IP 地址都以 10.
开头,如果有助于确定算法,那么冲突就会减少。
https://en.wikipedia.org/wiki/Hash_function
制作散列函数,然后将其切割成短的大小。例如:
(or some other prime numbers) ( 7 ^ 19 + 5 * 22 + 11 * 145 + 17 * 103 ) % size_of_short
你的任务通常是不可能的。所以我会从业务领域寻找捷径。
您需要映射所有个IP地址吗?您可以跳过 127.*.*.*
和 192.168.*.*
。但这还不够。你需要减少到 16 位,这是一个完整范围的摩擦:1 / 2^16
~ 1 / 64000
IPv4 是 4 个八位字节,因此您可以使用类似
的方式获得唯一的映射public static int asInt(byte[] addr) {
return (addr[0] & 0xFF) | ((addr[1] & 0xFF) << 8)
| ((addr[2] & 0xFF) << 16) | ((addr[3] & 0xFF) << 24);
}
或
public static int asInt(byte[] addr) {
return ByteBuffer.wrap(addr).readInt();
}
这为您提供了 232 个可能的值。如果您想将其映射到 16 位并确保它是唯一的,您需要将映射存储在其他地方,例如
final Map<Integer, Short> mapping = new ConcurrentHashMap<>();
int next = 0;
public short idFor(byte[] bytes) {
Integer i = asInt(bytes);
return mapping.computeIfAbsent(i, x -> next++);
}
在 Java 7 你可以做
public short idFor(byte[] bytes) {
Integer i = asInt(bytes);
synchronized(mapping) {
Short s = mapping.get(i);
if (s == null)
mapping.put(i, s = next++);
return s;
}
}
注意,一个 16 位值只能有 65536 个可能的唯一值。
如果你想要一个简单的散列,你可以使用像
这样的东西public short hash(int n) {
return (short) (n ^ (n >>> 16))
}
您可以添加聚合函数,例如
public short hash(int n) {
n *= 10191; // an odd prime of around 2^^16
return (short) (n ^ (n >>> 16))
}
不理想的是最高位不会以这种方式产生太多随机性。您可以改用 64 位计算。
public short hash(int n) {
long n2 = n * 0x6d0f27bdL;
n2 ^= (n2 >>> 21) ^ (n2 >>> 42);
return (short) (n ^ (n >>> 16) ^ (n >> 32));
}
我有一个新方法..检查代码,它保证您的代码是唯一的...
private static final int HASH_PRIME = 23;
public static short convertIP(String ip) {
String res = "";
for(String num: ip.split("\.")) {
int val = Integer.parseInt(num);
while(val>HASH_PRIME) {
val = val / HASH_PRIME;
}
if(new Random().nextInt(10) <= 4) {
res += convertChar(val);
} else {
res += val;
}
}
System.out.println("result = "+res); // the result could be anything like: T2264, 19WGE, TWGE, 1922G4, etc
return (short) (res.hashCode() % Short.MAX_VALUE);
}
private static char convertChar(int num) {
return (char)((num % 26) + 65);
}
public static void main(String[] args) {
System.out.println(convertIP("19.22.145.103"));
// the short code for the same IP will be unique majorly.. i.e. 24311, 23784, 31968, 16079, 23767 .. etc
}