理解传输层中UDP协议首部校验和以及校验和计算方法的Java实现
UDP,全称User Datagram Protocol,用户数据报协议,是TCP/IP四层参考模型中传输层的一种面向报文的、无连接的、不能保证可靠的、无拥塞控制的协议。UDP协议因为传输效率高,常用于即时通信,比如视频/语音聊天,直播等。
1. UDP数据报的格式
用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节,有四个字段组成,每个字段的长度都是两字节。各段意义如下:
- 源端口:源端口号。在需要对方回信时选用。不需要时可用全0。
- 目的端口:目的端口号。这在终点交付报文时必须要使用到。
- 长度:UDP用户数据报的长度,其最小值是8(仅首部)。
- 校验和:检测UDP用户数据报在传输中是否有错。有错就丢弃。
2. UDP校验和的计算
UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。
UDP检验和的计算方法是:
- 按每16位求和并在高位补0得到得出一个32位的求和结果;
- 如果这个32位的求和结果,高16位不为0,则高16位加低16位并且高位补0再得到一个32位的结果;
- 重复第2步直到高16位为0,将低16位取反,得到校验和。
3. UDP校验和计算方法的Java实现
一个实际例子:
key | hex |
---|---|
源IP地址 | 0x0aaa, 0x3bbf |
目的IP地址 | 0xd20e, 0x960d |
协议类型 | 0x0011 |
UDP长度 | 0x001c |
源端口 | 0xd123 |
目的端口 | 0x2742 |
长度 | 0x001c |
校验和 | 0x285c(用于验证) |
UDP数据 | 0x0000, 0x6c41, 0x5661, 0x0000, 0x0e00, 0xf8b6, 0xd401, 0x9313, 0x0000, 0x0000, 0x0000 |
Java实现:
public class CheckSumDemo {
public static void main(String[] args) {
/**
* 源IP
* 目的IP
* 协议类型
* UDP数据长度
* 源端口
* 目的端口
* UDP数据
* UDP数据
*/
int[] udp = {
0x0aaa, 0x3bbf,
0xd20e, 0x960d,
0x0011,
0x001c,
0xd123,
0x2742,
0x001c,
0x0000,0x6c41,0x5661,0x0000,0x0e00,0xf8b6,0xd401,0x9313,0x0000,0x0000,0x0000
};
int checkSum = 0x285c;
String s = udpCheckSum(udp);
System.out.println(s);
System.out.println(Integer.toHexString(checkSum).equals(s));
}
public static String udpCheckSum(int[] nums) {
int res = 0;
for (int num : nums) {
res += num;
if (res >>> 16 != 0) {
res = (res >>> 16) + (res & 0xffff);
}
}
return Integer.toHexString(~res).substring(4);
}
}
结果输出:
285c
true