一.校验和
使用补码计算校验和是一种常见的错误检测方法,应用于网络协议如IP和TCP。补码是二进制数的一种表示方法,可以有效地处理符号位和进位。下面是如何利用补码计算校验和的详细步骤和算数例子。
### 计算步骤
1. **将数据分块**:将数据分成16位(2字节)一块。
2. **求和**:将所有16位块的值求和,如果求和结果超过16位,则将高位的进位加回到结果中。
3. **取反**:将最终的和取反,得到校验和。
### 算数例子
假设我们有一个简单的数据序列,用于计算IP或TCP校验和。这里以16进制表示的数据序列为例:
```
4500 003C 1C46 4000 4006 B1E6 C0A8 0001 C0A8 00C7
```
#### 第一步:分块
将数据分成16位(2字节)一块:
```
4500
003C
1C46
4000
4006
B1E6
C0A8
0001
C0A8
00C7
```
#### 第二步:求和
将每个16位块转换为十进制并求和,注意每一步保持结果在16位以内(即如果有进位,则将进位加回到和中):
```
4500 -> 0x4500 = 17664
003C -> 0x003C = 60
1C46 -> 0x1C46 = 7238
4000 -> 0x4000 = 16384
4006 -> 0x4006 = 16390
B1E6 -> 0xB1E6 = 45542
C0A8 -> 0xC0A8 = 49320
0001 -> 0x0001 = 1
C0A8 -> 0xC0A8 = 49320
00C7 -> 0x00C7 = 199
```
将这些值相加:
```
17664 + 60 + 7238 + 16384 + 16390 + 45542 + 49320 + 1 + 49320 + 199 = 201118
```
由于这个和超过16位,我们需要将进位加回:
```
201118 = 0x313AE (以16进制表示)
将0x313AE分解为16位和进位部分:
0x313AE = 0x13AE + 0x30000 = 5038 + 3 = 5041 (0x13AE + 3 = 0x13B1)
```
所以最终的和为:
```
5041 = 0x13B1
```
#### 第三步:取反
将最终的和取反,得到校验和:
```
0x13B1 -> 取反 -> 0xEC4E
```
所以,校验和为:
```
0xEC4E
```
### 代码示例
下面是上述计算过程的Python实现:
```python
def calculate_checksum(data):
checksum = 0
# 将数据分块,每块16位(2字节)
for i in range(0, len(data), 2):
word = (data[i] << 8) + (data[i + 1] if (i + 1) < len(data) else 0)
checksum += word
# 如果有进位,则加回到结果中
if checksum > 0xFFFF:
checksum = (checksum & 0xFFFF) + 1
# 取反
checksum = ~checksum & 0xFFFF
return checksum
# 示例数据,以字节数组形式表示
data = [
0x45, 0x00, 0x00, 0x3C, 0x1C, 0x46, 0x40, 0x00,
0x40, 0x06, 0xB1, 0xE6, 0xC0, 0xA8, 0x00, 0x01,
0xC0, 0xA8, 0x00, 0xC7
]
# 计算校验和
checksum = calculate_checksum(data)
print("校验和: 0x{:04X}".format(checksum))
```
### 解释
1. **分块**:将数据分成16位一块。
2. **求和**:将所有块的值相加,如果超过16位,将进位部分加回到和中。
3. **取反**:将最终的和取反,得到校验和。
通过这个例子,我们可以清楚地看到如何利用补码计算校验和,这种方法在网络协议中广泛应用,确保数据传输的完整性和正确性。
解释
- 分块:将数据分成16位一块。
- 求和:将所有块的值相加,如果超过16位,将进位部分加回到和中。
- 取反:将最终的和取反,得到校验和。
通过这个例子,我们可以清楚地看到如何利用补码计算校验和,这种方法在网络协议中广泛应用,确保数据传输的完整性和正确性。
校验和的工作原理
校验和的目的是检测数据传输中的错误。当发送方发送数据时,它计算数据的校验和,并将这个校验和附加到数据包中。接收方在接收到数据包后,会重新计算数据的校验和,并将这个校验和与接收到的校验和进行比较。如果两个校验和相同,说明数据在传输过程中没有错误;如果不同,则表示数据在传输过程中发生了错误。
取反的作用
取反的目的是使得校验和的计算能够检测到尽可能多的错误类型。具体原因如下:
-
生成全零结果:取反后,当接收方计算校验和时,将所有数据块、校验和以及取反结果相加,如果数据传输没有错误,总和应该为全1(即0xFFFF)。这个全1结果取反后应该是全0(即0x0000)。如果数据在传输过程中发生了变化,总和将不会是全1,取反后也不会是全0,从而可以检测到错误。
-
错误检测的增强:通过取反,可以确保即使某些位翻转(例如1变成0或0变成1),校验和也能更有效地检测到这些错误。取反增加了检测到单个位错误和多位错误的可能性,从而增强了校验和的错误检测能力。
二.CRC校验(循环冗余码)