CRC校验

一、概念

CRC即循环冗余校验码(Cyclic Redundancy Check):是数据通信领域中最常用的一种差错校验码,其特征是信息

字段和检验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将

结构附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性。

 

二、计算

我们假设条件如下:

  (1)传送的原始消息msg:1,1,0,1,0,0,1,1

  (2)给定的生成多项式为gEx:x^4+x+1 即名称为CRC-4

从条件我们可以得到:

根据生成多项式得出生成多项式字码gExCode:1,0,0,1,1

根据生成多项式字码得到校验码码长r=5-1=4

根据原始消息我们得到原始消息表达式为:mEx=x^7+x^6+x^4+x^1+1

因此我们将原始消息向左移动4位:mEx*x^4=x^11+x^10+x^8+x^5+x^4

11 10 9 8 7 6 5 4 3 2 1 0 (多项式的次数)

1 1 0 1 0 0 1 1 0 0 0 0 (得到多项式相关的字码)

从上面的转换(当然也可以从原始消息直接看出)原始消息左移四位后的字码为:110100110000

然后我们用110100110000对生成多项式字码进行模2除法运算:

  1 1 0 1 0 0 1 1 0 0 0 0

^

  1 0 0 1 1

      ———————————

       0 1 0 0 1 0 1 1 0 0 0 0

       ^

          1 0 0 1 1

        ————————————

          0 0 0 0 1 1 1 0 0 0 0

                  ^

                     1 0 0 1 1

                   ————————

                     0 1 1 1 1 0 0

                     ^ 

                        1 0 0 1 1

                     ————————

                        0 1 1 0 1 0

                        ^ 1 0 0 1 1

                        ———————

                           0 1 0 0 1

所以校验码就是余数:1001

将余数放到原始消息的末尾就构成了最终发送的消息:

1 1 0 1 0 0 1 1 1 0 0 1

 

接收方拿到这个消息后,将其与生成多项式码进行模2除法,如果余数为0,则发送的消息没有差错;反之,则发送的消息存在差错。

 

三、错误检测 

当接收方收到数据后,用收到的数据对实现约定给定码进行模2除法,若余数为0,则认为数据传输无差错;若

余数不为0,则认为数据传输出现了错误,由于不知道错误发生在什么地方,因此不能进行自动纠正,一般的做法

就是丢弃接收到的数据。

 

四、Java代码来模拟这个算法

  1 public class CRCcheck {
  2    public static void main(String[]args) {
  3        String code="CRC-4";
  4        if(!generatePolyMap.containsKey(code)) {
  5            System.out.println("不存在此编码");
  6            return;
  7        }
  8        
  9        int[]gEx=generatePolyMap.get(code);
 10        int[] msg=send(new int[]{1,1,0,1,0,0,1,1},gEx);
 11        accept(msg,gEx,gEx.length-1);
 12    }
 13 
 14    //一些固定的事先约定好的生成多项式
 15    final static Map<String,int[]> generatePolyMap=new HashMap<String,int[]> ();
 16    static {
 17        generatePolyMap.put("CRC-4", new int[]{1,0,0,1,1});
 18        generatePolyMap.put("CRC-8", new int[]{1,0,0,1,1,0,0,0,1});
 19        generatePolyMap.put("CRC-12",new int[]{1,1,0,0,0,0,0,0,0,1,0,1,0,1});
 20    }
 21    
 22    
 23    public static int[] send(int[] msg,int[] gEx) {
 24        //校验码位数
 25        int r=gEx.length-1;
 26        
 27        //信息字码长度
 28        int k=msg.length;
 29        
 30        //最终发送信息长度,并生成最终放信息的空间
 31        int l=r+k;
 32        int[] m=new int[l];
 33        
 34        //初始化新的消息空间
 35        for(int i=0;i<l;i++) {
 36            m[i]=0;
 37        }
 38        
 39        //将原始消息左移r位
 40        System.out.print("原始消息:");
 41        for(int i=0;i<k;i++) {
 42            System.out.print(msg[i]+"\t");
 43            m[i]=msg[i];
 44        }
 45        
 46        System.out.println();
 47        
 48        int[] remainder=new int[r];
 49        int[] tmp=new int[l];
 50        for(int i=0;i<l;i++) {
 51            tmp[i]=m[i];
 52        }
 53        
 54        int[] result=modDivNum(tmp,gEx,r,remainder,true);
 55        
 56        System.out.print("检验码:  ");
 57        for(int i=0;i<result.length;i++) {
 58            System.out.print(result[i]+"\t");
 59        }
 60        System.out.println();
 61        
 62        
 63        int t=1;
 64        for(int i=result.length-1;i>=0;i--) {
 65            m[l-t]=result[i];
 66            t++;
 67        }
 68        
 69        System.out.print("发送消息:");
 70        for(int i=0;i<m.length;i++) {
 71            System.out.print(m[i]+"\t");
 72        }
 73        System.out.println();
 74        return m;
 75    }
 76    
 77    
 78    public static void accept(int[]msg,int[]gEx,int r) {
 79        boolean flag=validate(msg,gEx,r);
 80        if(flag) {
 81            System.out.println("接收的消息完好无损");
 82            return;
 83        }
 84        System.out.println("接收的消息有损伤");
 85    }
 86    
 87    private static boolean validate(int[] sendMsg,int[] gEx,int r) {
 88        if(sendMsg.length<r) {
 89            for(int i=0;i<sendMsg.length;i++) {
 90                if(sendMsg[i]==1) {
 91                    return false;
 92                }
 93            }
 94            
 95            return true;
 96        }
 97        for(int i=0;i<gEx.length;i++) {
 98            sendMsg[i]=gEx[i]^sendMsg[i];
 99        }
100        
101        boolean flag=true;
102        int firstSerizeZeroCount=0;
103        int count=0;
104        for(int i=0;i<sendMsg.length;i++) {
105            if(flag&&sendMsg[i]==0) {
106                firstSerizeZeroCount++;
107                continue;
108            }
109            if(sendMsg[i]==1) {
110                flag=false;
111            }
112            count++;
113        }
114        
115        int[] tmpMsg=new int[count];
116        int k=0;
117        for(int i=firstSerizeZeroCount;i<sendMsg.length;i++) {
118            tmpMsg[k++]=sendMsg[i];
119        }
120        
121        sendMsg=tmpMsg;
122        return validate(sendMsg,gEx,r) ;
123    }
124    
125    private static int[] modDivNum(int[]m,int[]gEx,int r,int[] result,boolean f) {
126        if(!f && result.length<=r) {
127            return result;
128        }
129        
130        for(int i=0;i<gEx.length;i++) {
131            m[i]=gEx[i]^m[i];
132        }
133        
134        
135        boolean flag=true;
136        int count=0;
137        int n=0;
138        for(int i=0;i<m.length;i++) {
139            if(m[i]==1) {
140                flag=false;
141            }
142            
143            if(flag&&m[i]==0) {//前面的都是0
144                n++;  //记录前面0的个数
145                continue;
146            }
147            
148            count++;
149        }
150        
151        result=new int[count];
152        
153        int j=0;
154        for(int i=n;i<m.length;i++) {
155            result[j++]=m[i];
156        }
157        
158        m=result;
159        
160        return modDivNum(m,gEx,r,result,false);
161    }
162     
163 }
View Code

 

posted on 2015-06-10 14:04  飞机说之代码也疯狂  阅读(603)  评论(0编辑  收藏  举报