CRC 校验 C# 实现法

 

计算机网络这门课提到过 CRC 检验。用 C# 模拟实现它主要关注模二除法和字节向整型数组的转换。

 

这里的实现方法效率很低,不过思想却很清晰。先把代码列出来:

 

    public class Buffoon_CRC_CCITT

    {

        private int[] Multinomial;

       

        public Buffoon_CRC_CCITT()

        {

            Multinomial = new int[17];

            for (int i = 0; i < 17; ++i)

            {

                if (i == 0 || i == 4 || i == 11 || i == 16) Multinomial[i] = 1;

                else Multinomial[i] = 0;

            }

        }

 

        public byte[] AddCRCCodes(byte[] bytes)

        {

            int[] source = ToArray(bytes);

            int[] codes = new int[source.Length + Multinomial.Length - 1];

 

            source.CopyTo(codes, 0);

 

            int startIndex = 0;

 

            for (; startIndex < source.Length; ++startIndex)

            {

                if (codes[startIndex] == 1) break;

            }

 

            for (int i = startIndex; i < source.Length; )

            {

                for (int j = 0; j < Multinomial.Length; ++j)

                {

                    codes[i + j] = (codes[i + j] + Multinomial[j]) % 2;

                }

 

                for (; i < source.Length; ++i)

                {

                    if (codes[i] == 1) break;

                }

            }

 

            source.CopyTo(codes, 0);

 

            return FromArray(codes);

        }

 

        public bool Verify(byte[] bytes, out byte[] source)

        {

            int[] codes = ToArray(bytes);

            int[] _source = new int[codes.Length - Multinomial.Length + 1];

 

            Array.Copy(codes, _source, _source.Length);

 

            int startIndex = 0;

 

            for (; startIndex < _source.Length; ++startIndex)

            {

                if (codes[startIndex] == 1) break;

            }

 

            for (int i = startIndex; i < _source.Length; )

            {

                for (int j = 0; j < Multinomial.Length; ++j)

                {

                    codes[i + j] = (codes[i + j] + Multinomial[j]) % 2;

                }

 

                for (; i < _source.Length; ++i)

                {

                    if (codes[i] == 1) break;

                }

            }

 

            for (int i = codes.Length - 1; i > codes.Length - Multinomial.Length + 1; --i)

            {

                if (codes[i] == 1)

                {

                    source = null;

                    return false;

                }

            }

 

            source = FromArray(_source);

            return true;

        }

 

        private int[] ToArray(byte[] b)

        {

            int[] arr = new int[b.Length * 8];

 

            for (int i = 0; i < b.Length; ++i)

            {

                arr[i * 8] = (b[i] & 0x80) >> 7;

                arr[i * 8 + 1] = (b[i] & 0x40) >> 6;

                arr[i * 8 + 2] = (b[i] & 0x20) >> 5;

                arr[i * 8 + 3] = (b[i] & 0x10) >> 4;

                arr[i * 8 + 4] = (b[i] & 0x08) >> 3;

                arr[i * 8 + 5] = (b[i] & 0x04) >> 2;

                arr[i * 8 + 6] = (b[i] & 0x02) >> 1;

                arr[i * 8 + 7] = b[i] & 0x01;

            }

 

            for (int i = 0; i < arr.Length; ++i)

            {

                Debug.Assert(arr[i] == 1 || arr[i] == 0);

            }

 

            return arr;

        }

 

        private byte[] FromArray(int[] arr)

        {

            Debug.Assert(arr.Length % 8 == 0);

 

            for (int i = 0; i < arr.Length; ++i)

            {

                Debug.Assert(arr[i] == 1 || arr[i] == 0);

            }

 

            byte[] bytes = new byte[arr.Length / 8];

 

            for (int i = 0; i < arr.Length; i += 8)

            {

                int value = 0;

                for (int j = 0; j < 8; ++j)

                {

                    if (arr[i + j] == 1) value += (int)Math.Pow((double)2, (double)(7 - j));

                }

 

                bytes[i / 8] = (byte)value;

            }

 

            return bytes;

        }

    }

 

As you can see, 我把这个类取名为“小丑_CRC_CCITT”。因为我觉得这个类干得事就是多此一举,没什么用,只会捣乱。不过这个练习对提高对二进制数的控制能力比较有用。

 

这个程序的思想就是把一个给定的字节数组转换成由 0, 1 组成的整型数组(这个整型数组用来表示二进制序列),然后对这个二进制数组进行运算。所以,一开始先看 FromArray() ToArray() 这两个函数。FromArray() 用来把二进制整型数组转换成字节数组。而 ToArray() 就是把字节数组转换成整型数组。

 

有这个两个函数垫底,我们就可以看给一个二进制流加上 CRC 校验码了。AddCRCCodes() 就是干这个事的。它用模二除法算出给定的字节数组对应的 CRC 校验码。

 

多项式用的是 CCITT 标准。即 多项式 = x^16 + x^12 + x^5 + 1。注意构造函数在初始化这个多项式的代码。我用多项式的 0 索引的元素表示最高位。

 

回过头来继续看 AddCRCCodes()。它把参数转换成整型数组,然后进行模二除法,算出余项。把余项附加到原来的字节数组上。最后把这个附加了余项的字节数组返回。由于 CCITT 的标准和 CRC-16 都是 16 次的多项式,故附加的余项长度正好为 2 个字节。注意,多项式的长度是 17 位,要比余项多一位。

 

知道如何加 CRC 余项后,校验的过程也就如法炮制了。它对应的函数为 Verify()

 

这个类在更改了构造函数对 Multinomial (多项式) 的初始化代码后,很容易地变成针对任意一个长度为 8 * n + 1 位多项式的 CRC 校验类。

 

当然老师验收这个题的时候,要我把结果用手算一遍,再和机器的输出比较。一样的话才算分。幸亏我当时写这个程序的时候注意了通用性。验收的时候把多项式改成 9 位的了。如果用手算 17 的多项式,那……

转载于:https://www.cnblogs.com/ydong/archive/2007/05/03/735204.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、循环校验码(CRC码):是数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。   2、生成CRC码的基本原理:任意一个由二进制串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。   3、CRC码集选择的原则:若设码字长度为N,信息字段为K校验字段为R(N=K+R),则对于CRC码集中的任一码字,存在且仅存在一个R次多项式g(x),使得   V(x)=A(x)g(x)=xRm(x)+r(x);   其中: m(x)为K次信息多项式, r(x)为R-1次校验多项式,   g(x)称为生成多项式:   g(x)=g0+g1x+ g2x2+...+g(R-1)x(R-1)+gRxR   发送方通过指定的g(x)产生CRC码字,接收方则通过该g(x)来验证收到的CRC码字。   4、CRC校验码软件生成方:   借助于多项式除,其余数为校验字段。   例如:信息字段代码为: 1011001;对应m(x)=x6+x4+x3+1   假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代码为: 11001   x4m(x)=x10+x8+x7+x4 对应的代码记为:10110010000;   采用多项式除: 得余数为: 1010 (即校验字段为:1010)   发送方:发出的传输字段为: 1 0 1 1 0 0 1 1 0 10   信息字段 校验字段   接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除)   如果能够除尽,则正确,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值