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代码来模拟这个算法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }