crc循环校验原理和实现博客分类:天天编程CRC32CRC校验java源码CRC原理CRC161.CRC简介CRC(cyclicalredundancycheck)循环冗余校验,在《计算机组成原理》里面有这个知识点。类似的校验有奇偶校验。可以简单的理解成在发送数据后面加上这个验证码,判断前面数据是否正确。根据需要的校验位数不同,有CRC8、CRC16、CRC32、CRC128...再以后就不用这个乐,可以使用md5校验。2.简介CRC校验步骤CRC的校验方法网上很多。就说了,用发送的数据来除以校验公式,使其最后的余数为0。3.举例字母a的CRC16校验(CRC-CCITT)采用的校验公式为G(X)=X16+X12+X5+1CRC16校验产生的校验码为16位,就是2个字节。a对应的ascii为0x61,这个就是得到的结果。4.C语言实现按第三届手算的过程,非常好理解。Cpp代码1.intmain()2.{3.//这里int型是占4个字节。0x00000000,当然值、只用到后2个字节,也可以直接用unsignedshort,用无符号是因为C语言里面没有无符号移位的功能。4.unsignedintcrc='a';//计算字符a的crc16校验码5.//右移8位,和手动计算一样,左移相当于补0,这里相当于直接补了8个0,开始计算。6.crc=8;//=相当余crc=crc8;7.//计算8次。8.for(inti=0;i8;i++)9.{10.//如果最高位是1的话需要计算,如果不是直接左移。(左移的操作可以想象成补0)11.if((crc&0x8000)!=0)12.{13.crc=1;14.crc=crc^0x1021;//这个说明用的是CRC16x16+x12+x5+1.15.}16.else17.{18.crc=1;19.}20.}21.//取后16位,如果用的是crc使用的是unsignedshort就不需要这一步了。22.crc=crc&0xffff;23.//输出。24.std::coutcrcstd::endl;25.}5.多字节校验上面是讲一个字节时的校验,当有两个字节时,就需要以下几步,0x6162:01100001011000100x6162=0x6100+0x0062计算过程如下:下面是实现Java代码1.publicstaticvoidmain(String[]args){2.inta=0x61;3.intb=0x62;4.//先计算a的CRC5.intCRC=a;6.CRC=8;7.for(inti=0;i8;i++){8.if((CRC&0x8000)!=0){9.CRC=1;10.CRC=CRC^0x1021;11.}else{12.CRC=1;13.}14.}15.System.out.println((Integer.toHexString(CRC&0xffff)));16.//将得到的CRC的的前8位和b相异或,然后取前八位,进行CRC计算。17.intCRCtemp=((b8)^CRC)&0xff00;18.for(inti=0;i8;i++){19.if((CRCtemp&0x8000)!=0){20.CRCtemp=1;21.CRCtemp=CRCtemp^0x1021;22.}else{23.CRCtemp=1;24.}25.}26.//将新计算的CRCtemp和原来计算的CRC后八位进行异或,当然,这里旧的CRC就变成了高位27.System.out.println(Integer.toHexString((CRCtemp^(CRC8))&0xffff));28.}6.改进后的算法。网上很多计算CRC的例子,都有一个数组来计算。这个数组是256的大小,是对0x00--0xff中的每一个字节都进行计算,储存起来。用的时候直接使用。结合上面的实现,就有了如下代码。Java代码1.publicstaticvoidgetCRC16(byte[]bs){2.//表对应00-ff所有的CRC结果。3.int[]table={0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,0x1231,4.0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,0x2462,0x3443,0x0420,5.0x1401,0x64e6,0x74c7,0x44a4,0x5485,0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,0x3653,0x2672,0x1611,0x0630,0x76d7,6.0x66f6,0x5695,0x46b4,0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,7.0x3823,0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,0xdbfd,8.0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,0xedae,0xfd8f,0xcdec,9.0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,10.0xaf3a,0x9f59,0x8f78,0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,11.0x6067,0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,0xb5ea,12.0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,0xa7db,0xb7fa,0x8799,13.0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,14.0x89e9,0xb98a,0xa9ab,0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,15.0xbb9a,0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,0x7c26,16.0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,0x6e17,0x7e36,0x4e55,17.0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0};18.intcrc=0;19.for(inti=0;ibs.length;i++){20.crc=((crc8)^table[((crc8)^bs[i])&0xff]);21.}22.System.out.println(Integer.toHexString(crc&0xffff));23.}7.反向校验(这一节内容我也不大清楚,所以你看懂基本会很吃力,本节建议扫一眼就行)在不同的系统,存字节的顺序也可能不一样,还有在传输中先传送低字节(也是低地址,小端),所以为了节省计算,就有反向校验。这个不能多解释,直接看代码会理解的好一些。Java代码1.//生成一个字节的CRC32,注意:这个并不是最终结果,因为在反向CRC的时候,CRC的初始值为0xffffffff,这里是计算16*16的table表,方便后面计算。2.publicstaticintcheckOneCRC(intb){3.intcrc=b;4.for(inti=0;i8;i++){5.//比较最低位。6.if((crc&1)==1){7.//和正向的不一样,这里比较的是最低位。并且换成了友移,方程式也变了8.//正向的0x04C11DB7,变成了,0xEDB88320(其实只是反过来算)9.crc=(crc1)^0xedb88320;10.}else{11.crc=1;12.}13.}14.returncrc;15.}这样计算出来256的table表后,就可以计算结果了。Java代码1.publicstaticvoidmain(String[]args){2.int[]bs={0x1c,0xdf,0x44,0x21,0,1,0x36,0xde,0x22,0x69,0x88,0xa8,0x29,0x4d};3.//规定的crc处置为111111...4.intcrc=0xffffffff;5.for(inti=0;ibs.length;i++){6.crc=((crc8)^table[(crc^bs[i])&0xff]);7.}8.crc=crc^0xffffffff;//(和取反一样)9.System.out.println(Integer.toHexString(crc));10.}8.java自带的CRC32校验。8.1使用这里使用的CRC32反向校验。如第七节。Java代码1.publicstaticvoidmain(String[]args){2.byte[]bss={'a'};3.CRC32c=newCRC32();4.c.update(bss[0]);5.System.out.println(Long.toHexString(c.getValue()));6.}8.2myeclispe里的源码源码很少,都是native方法,里面的实现也就是第七节的代码,只是那个表格的内容不是再计算的,是这样的表格。Java代码1.int[]table={0x00000000,0x77073096,0xee0e612c,0x990951ba,2.0x076dc419,0x706af48f,0xe963a535,0x9e6495a3,0x0edb8832,3.0x79dcb8a4,0xe0d5e91e,0x97d2d988,0x09b64c2b,0x7eb17cbd,4.0xe7b82d07,0x90bf1d91,0x1d