ip、ip:port和long的相互转换

说明:转换仅支持ipv4地址

可实行性分析

ipv4 地址格式: [0-255].[0-255].[0-255].[0-255]

ipv4地址分为4段, 每一段是一个[0-255]之间的数字,可见第一段可使用的数字个数为256=2^8 , 刚好是一个字节能表示的无符号整数范围。那4段就是4个字节。 也就是说只需要4个字节就能存下ip地址, java中一个int是4个字节,一个int就能表示一个ipv4地址。

端口的范围是 0-65535 , 刚好是2^16 个数字, 是两个字节能表示的无符号整数范围。

所以实际上存储 ip:port 组合只需要6个字节, java中long是8个字节, 完全能够表示ip:port组合。

代码实现

实现依赖了guava来处理整数和字节数组的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import sun.net.util.IPAddressUtil;

import java.util.Arrays;

/**
* ip、ip:port 和 int、long的相互转换
*
* @author huaxiaoer
* @since 2020-06-17
*/
public class IpAddressUtils {

/**
* ip 转换成int型, 结果可能为负数, 如果要求正数,使用 ipToLong
* @param ipv4
* @param port
* @return
*/
public static int ipToInt(String ipv4){
byte[] address = IPAddressUtil.textToNumericFormatV4(ipv4);
return Ints.fromByteArray(address);
}

/**
* ip 转换成long型
* @param ipv4
* @param port
* @return
*/
public static long ipToLong(String ipv4){
return ipToInt(ipv4) & 0xFFFFFFFFL;
}

/**
* int 转换为ip
* @param num
*/
public static String intToIp(int num){
byte[] bytes = Ints.toByteArray(num);
return (bytes[0] & 0xff) + "." + (bytes[1] & 0xff) + "." + (bytes[2] & 0xff) + "." + (bytes[3] & 0xff);
}


/**
* int 转换为ip
* @param num
*/
public static String longToIp(long num){
byte[] bytes = Longs.toByteArray(num);
return (bytes[4] & 0xff) + "." + (bytes[5] & 0xff) + "." + (bytes[6] & 0xff) + "." + (bytes[7] & 0xff);
}

/**
* ip:port 组合转换成long型
* @param ipv4
* @param port
* @return
*/
public static long ipPortToLong(String ipv4, int port){
byte[] address = IPAddressUtil.textToNumericFormatV4(ipv4);
byte[] socket = Bytes.concat( Ints.toByteArray(port),address);
return Longs.fromByteArray(socket);
}

/**
* long 转换为ip:port 字符串
* @param num
*/
public static String longToIpPortStr(long num){
Object[] ipPort = longToIpPort(num);
return ipPort[0] + ":" + ipPort[1];
}

/**
* long 转换为[ip,port]数组
* @param num
* @return [ip,port]
*/
public static Object[] longToIpPort(long num){
byte[] bytes = Longs.toByteArray(num);
byte[] portBytes = Arrays.copyOfRange(bytes, 0, 4);
byte[] ipBytes = Arrays.copyOfRange(bytes, 4, 8);
String ip = (ipBytes[0] & 0xff) + "." + (ipBytes[1] & 0xff) + "." + (ipBytes[2] & 0xff) + "." + (ipBytes[3] & 0xff);
int port = Ints.fromByteArray(portBytes);
return new Object[]{ip,port};
}
}