一、题外话
说来惭愧,一开始是考虑写关于CRC检错技术更深层次数学原理的,然而在翻看《Basic Algebra》后,我果断放弃了这种不切实际的想法。个人觉得不是因为本人数学水平差或者能力差,而是研究生教材知识概念具有一定的连贯性,需要花大量时间研读。不过呢,我还是找到一本适合了解CRC技术的著作《纠错码的代数理论》---冯克勤,对数学感兴趣的朋友也可以在业余时间品读一下全书。
用国内搜索引擎搜索关于CRC检错技术的文章或者博客,内容也基本都是千篇一律,基本都是介绍如何模2运算。写下这篇文章,希望能够弥补一下国内所谓技术文章的部分不足之处。当然,最主要的还是帮助自己和读者有所提高。
二、循环冗余校检码来源
CRC这个缩略词,在我看来可以有两种理解:一种是Cyclic Redundancy Check,即循环冗余检测技术;另一种则是Cyclic Redundance Code,即循环冗余校检码。在计算机网络中,基本上都是使用前一种,但是我也是见过能够理解成后者的说法的。
我第一次接触到CRC这个词是在计算机网络教材讲数据链路层帧的差错检测部分。实际的网络通信链路并非是理想的,即在网络通信中自身的电磁信号由于会受到外界电磁波或脉冲干扰的影响,会在比特传输过程中出现比特差错(属于传输差错的一种),因此为了保证计算机网络数据传输的可靠性,在网路传输数据时,必须采用差错检测措施。
在计算机网络发展过程中,数学起到了至关重要的作用。正当通信专家对差错检测措施一筹莫展的时候,团队中的数学家将抽象代数中的二元素伽罗瓦域(GF(2))引入,告诉我们可以通过数学手段解决数据的比特差错检测问题。其余的情况只能靠你们脑补了。
三、循环冗余校检原理
《计算机网络 第五版》---谢希仁所著的教材通过例子对循环冗余检验原理的原理说明如下:
在发送端,先把数据划分为组,假定每组k个比特。现假定待传送的数据M=101001(k=6)。CRC运算就是在数据M的后面添加供差错检测用的n位冗余码,然后构成一个帧发送出去,一共发送(k+n)位。在所要发送的数据后面增加n位的冗余码,虽然增大了数据传输的开销,但却可以进行差错检测。当传输可能出现错误时,付出这种代价往往是很值得的。
这n位冗余码可用以下方法得出。用二进制的模2运算进行乘M的运算,这相当于在M后面添加n个0。得到的(k+n)位的数除以收发双方事先商定的长度为(n+1)位除数P,得出的商是Q而余数是R(n位,比P少一位)。关于除数P下面还要介绍。在图1所示的例子中,M=101001(即k=6)。假定除数P=1103(即n=3)。经模2除法运算后的结果是:商Q=110101(这个商并没有什么用处),而余数R=001。这个余数R就作为冗余码拼接在数据M的后面发送出去。这种为了进行检错而添加的冗余码常称为帧检验序列FCS(Frame Check Sequence)。因此加上FCS后发送的帧是101001001(即),共有(k+n)位。
图1 循环冗余检测原理例子
顺便说一下,循环冗余检验CRC和帧检验序列FCS并不是同一概念。CRC是一种检错方法,而FCS是添加在数据后面的冗余码,在检错方法上可以选用CRC,但也可以不选用CRC。
在接受端把接收到的数据以帧为单位进行CRC检验:把收到的每一个帧都除以同样的除数P(模2运算),然后检查得到的余数R。
如果在传输过程中无差错,那么经过CRC检验后得出的余数R肯定是0。但如果出现误码,那么余数R仍等于零的概率是非常非常小的(可以通过不太复杂的概率计算得出)。
总之,在接收端对收到的每一帧经过CRC检验后,有以下两种情况:
1)若得出的余数R=0,则判定这个帧没有差错,即接受(accept);
2)若余数R!=0,则判定这个帧有差错,即丢弃(discard)。
一种较方便的方法时用多项式来表示循环冗余检验过程。在上面的例子中,用多项式 表示上面的除数P=1101(最高位对应于,最低位对应于)。多项式P(X)称为生成多项式。现在广泛使用的生成多项式P(X)有以下几种:
在数据链路层,发送端帧检验序列FCS的生成和接收端的CRC检验都是用硬件完成的,处理很迅速,因此并不会延误数据的传输。
小结:
小结一下上述教材内容所提到的内容:
1)什么叫"模2运算"?
通过一个例子的话我想能够在你脑子里形成清晰的概念。假如一个数k被任意的数除,那么它产生的余数必定是在[0,n)区间中。即x mod n ∈ [0, n)。模2运算也是符合这种理论的,即模2运算就是指结果只能是在[0,2)区间中取整数值的运算,显然"模2运算"就是指结果只能为0、1的特殊二进制运算。
2)为什么"模2运算"属于特殊二进制运算,必须突出"特殊"二字?
第一点,"模2运算"和"二进制运算"名字本身就不同,因此类比的时候使用"特殊"二字;第二点,两者的运算其实是有区别,"模2运算"既不进位也不退位,而"二进制运算"和"十进制运算"均需要进、退位。
3)循环冗余检验只是数学检错技术中的一种,还有奇偶校检等数学手段。而且循环冗余检验并不能保证100%正确,只能说接近100%。
4)生成多项式的应用:
图2 PPP帧格式
图3 MAC帧格式
从图2、3可以看出,CRC-16应用于PPP帧(16位的CRC-CCITT用于HDLC链路),CRC-32应用于MAC帧。而且,CRC-32比CRC-16可靠性要高。
-----------------------------------------------------------------------------------上 帝 的 分 界 线------------------------------------------------------------------------------
这部分谈论的是CRC检错技术基于的数学原理,参考文章是GF(2)---wikipedia。
GF(2) (also F2, Z/2Z or Z2) is the Galois field of two elements. It is the smallest finite field.
wikipedia给出的定义如下:GF(2)是二元素伽罗瓦域,也是最小的有限域。
"模2运算"类比二进制运算的差别---无进、退位是由GF(2)性质决定的。
小结:
模2运算是特殊的四则运算,分为加模2运算、减模2运算、乘模2运算、除模2运算。
四、循环冗余检错技术实战
首先分析生成多项式,显然n=3,因此循环冗余码应为3位二进制数。生成多项式代表的二进制除数P=1001,发送的数据为101110,则真实的被除数为101110000。进行减模2运算(异或运算)如下:
图4 模2运算步骤
于是得到FCS为011,因此发送数据实际为101110011(除以1001余数为0,读者可自行尝试)。注意到,在运算的时候,每次都会往后退一位,即第一位每次都是被消掉的。
五、曾经的困惑暨反思
当我一开始接触计算网络中CRC检测技术的时候,由于经验以及知识的匮乏,一直有一个问题困扰着我:如果网卡在发送帧时自动添加FCS到帧尾,那么接收端是如何判断的呢?接收端又不知道发送端用的除数P是多少。
现在回想起来,其实这种质问的想法似乎还挺有道理的。对于这个问题,其实这篇文章当中已经给出了问题的答案:计算机网络通信中,我们对生成多项式(除数)作了统一的标准,即针对不同的帧,发送端网卡添加不同的FCS,而接受端网卡知道相应帧该用CRC-16还是CRC-32来检错。
问题解决了,接着简单谈谈在学习CRC检错技术后的有啥收获吧。说实在的,之前只知道线性代数、数论等在计算机算法领域有着广泛的应用,没有想到计算机领域还用到了群论这门高深的学问。莎士比亚有句名言:"聪明的人总认为自己是笨蛋,而笨蛋却总以为自己很聪明"。再接再励,在工作中坚持学习吧。