UDP协议首部校验和

#简介

UDP,全称User Datagram Protocol,用户数据报协议,**是TCP/IP四层参考模型中传输层的一种面向报文的、无连接的、不能保证可靠的、无拥塞控制的协议 **。UDP协议因为传输效率高,常用于即时通信,比如视频/语音聊天,直播等。

#UDP数据报的格式

用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节,有四个字段组成,每个字段的长度都是两字节。各段意义如下:

  • 源端口:源端口号。在需要对方回信时选用。不需要时可用全0。
  • 目的端口:目的端口号。这在终点交付报文时必须要使用到。
  • 长度:UDP用户数据报的长度,其最小值是8(仅首部)。
  • 校验和:检测UDP用户数据报在传输中是否有错。有错就丢弃。

udp-protocol-header.png

#UDP校验和的计算

UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。

UDP检验和的计算方法是:

  • 按每16位求和并在高位补0得到得出一个32位的求和结果;
  • 如果这个32位的求和结果,高16位不为0,则高16位加低16位并且高位补0再得到一个32位的结果;
  • 重复第2步直到高16位为0,将低16位取反,得到校验和。

#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