题图来自网络
TCP/IP 体系中有两种校验机制:CRC 校验与校验和,用于保证消息的完整性。CRC 校验用于整个以太网帧的校验,32 位的校验码被添加到以太网帧的最后四个字节。更为常用的是校验和机制,被用于 IP,ICMP,TCP,UDP 等三四层协议中。
运算机制
校验和机制的运算很简单,计算方法为将校验范围内的字节取反相加,校验方法为将校验范围内的字节与校验和相加,如果结果为 1 ,则代表没有传输错误发生。
取反相加
取反相加,相加就相加了,为什么要取反?取反是因为上文提到的校验方式:发送的消息字段为 1011,校验和取反相加:0100,最终发送的消息为 1011 0100
接收端验证消息时,将消息字段与校验和字段通通相加,得到:1011 + 0100 = 1111,全部为1,所以没有错误发生。
可见取反相加是为了能在校验时,直接将消息字段和校验码相加,通过结果是否为全 1 来判断是否有错误。利用的是二进制加法 1+1 = 0 的特性。
作为对比,小明同学提出一种不需要取反的方法,发送端消息字段相加得到校验位。接收端只将消息字段相加,然后和校验字段做比较。相当于发送端节省了取反的开销,而接收端的开销从做一次二进制加法+与全1做比较 变成 一次比较(数据字段相加后与校验和字段比较)。那么两种方法孰优孰劣?为什么 TCP/IP 选择了前者。作者目前的理解是,当时的设计者基于当时的硬件开销状况,选择了目前使用的这套校验机制。可能现在的开销情况会有所不同,需要一些更细致的硬件实现细节和实验来了解。
多做无功
显然校验和只能发现奇数位错误,曾经学过通信原理的小明同学表示,为什么不用汉明码,最小码距 3 ,可以检 2 个错,还能纠 1 个错。对于在三层以上使用的校验和来说,检错太多可以算得上是多做无功,因为数据已经通过了二层的检验机制,去除了那些受到了严重错误的数据。过大的校验开销并不实用。
溢出处理
两个数相加,可能是 8 位,也可能是 16 位,亦或者是 32 位,总有可能会溢出,这多了一位如何是好。
简单 把这溢出的 1 加到最低位去
这里只需要一个固定的生成/验证校验机制,并不是运算。
那如果又溢出了呢?
那就再加到最低位去。
能少做就少做
对每个数先取