一、计算机中的进制:二进制与十六进制
1. 十进制(Decimal)
-
特点:用0-9表示,逢10进1。
-
例子:数字
123
表示 1×102+2×101+3×1001×102+2×101+3×100。
2. 二进制(Binary)
-
特点:用0和1表示,逢2进1。
-
例子:二进制
1×23+1×22+0×21+1×20=8+4+0+1=131×23+1×22+0×21+1×20=8+4+0+1=131101
转为十进制: -
快速转换:
-
二进制 → 十进制:记住权值 20=1,21=2,22=4,23=820=1,21=2,22=4,23=8,逐位相加。
-
十进制 → 二进制:不断除以2取余数,倒序排列。
13 ÷ 2 = 6 余 1 → 最低位 6 ÷ 2 = 3 余 0 3 ÷ 2 = 1 余 1 1 ÷ 2 = 0 余 1 → 最高位 结果为 1101
-
3. 十六进制(Hexadecimal)
-
特点:用0-9和A-F(A=10, B=11, ..., F=15)表示,逢16进1。
-
例子:
1×162+10×161+3×160=256+160+3=4191×162+10×161+3×160=256+160+3=4191A3
转为十进制: -
二进制 ↔ 十六进制快速转换:
-
每4位二进制对应1位十六进制(不足补0)。
二进制 1101 0011 → D3(1101=D, 0011=3) 十六进制 F → 1111
-
二、为什么UDP需要校验和?
-
核心目的:检测数据传输过程中是否发生位错误(如电磁干扰导致0变1或1变0)。
-
设计特点:
-
UDP本身不保证可靠性,但校验和是可选的安全基线。
-
校验失败时,UDP直接丢弃数据包,不会重传。
-
三、UDP校验和的计算步骤
1. 数据分片
-
将UDP报文(头部+数据)按16位(2字节)分组,不足则补0。
示例数据(十六进制): 源端口:11 22 目的端口:33 44 长度:00 08(8字节) 校验和:00 00(初始值) 数据:AA BB CC DD → 分片为:1122, 3344, 0008, 0000, AABB, CCDD
2. 反码求和
-
反码(Ones' Complement):二进制数按位取反(0→1,1→0)。
-
计算步骤:
-
所有16位分片按二进制相加。
-
若结果超过16位(溢出),将溢出部分加到低位(循环进位)。
-
对最终结果取反码,即为校验和。
-
3. 实际计算示例
-
示例数据(用十六进制简化计算):
分片:0x1122, 0x3344, 0x0008, 0x0000, 0xAABB, 0xCCDD
-
步骤1:十六进制直接相加:
1122+3344+0008+0000+AABB+CCDD1122+3344+0008+0000+AABB+CCDD转换为十进制计算:
1122 = 4386 3344 = 13124 0008 = 8 0000 = 0 AABB = 43707 CCDD = 52445 总和 = 4386 + 13124 + 8 + 0 + 43707 + 52445 = 113,670
-
步骤2:处理溢出:
-
113,670 转为二进制:
11011101100000110
(17位,溢出1位)。 -
循环进位:将溢出的1加到低位:
剩余16位:1011101100000110(十进制为 47,622) 加溢出位:47,622 + 1 = 47,623 → 0xB9E7(十六进制)
-
-
步骤3:取反码:
-
0xB9E7 的二进制:
1011100111100111
-
取反码:
0100011000011000
→ 0x4618
-
-
最终校验和:0x4618。
四、验证校验和的接收方行为
-
接收方将整个UDP报文(含校验和)按同样步骤计算。
-
若计算结果为
0xFFFF
(全1),说明数据未损坏。 -
否则,数据包被丢弃。
五、趣味记忆法
1. 二进制加法 → 堆积木
-
想象每16位分片是一堆积木,总和超过高度(溢出)时,把多余的积木移到最下面。
2. 校验和 → 安全封印
-
发送方将数据包“封印”(校验和),接收方验证封印是否完整。
六、动手实验
1. 用Python计算UDP校验和
import numpy as npdef udp_checksum(data):# 将数据按16位分组(假设data为字节流)if len(data) % 2 != 0:data += b'\x00' # 补0words = np.frombuffer(data, dtype='>H') # 大端序读取16位total = sum(words)# 处理溢出(循环进位)while total > 0xFFFF:total = (total & 0xFFFF) + (total >> 16)# 取反码return np.uint16(~total)# 示例数据 data = bytes.fromhex('1122334400080000AABBCCDD') checksum = udp_checksum(data) print(f"校验和: 0x{checksum:04X}") # 输出 0x4618
总结
-
进制基础:二进制和十六进制是计算机的“母语”,掌握快速转换是理解底层机制的关键。
-
UDP校验和:本质是反码求和,通过简单的位运算实现数据完整性检查。
-
学习技巧:用代码和实际数据包验证理论,将抽象计算具象化。