前言:网上查了很多,CRC计算时,除数长度太长无法计算,所以写此文章。希望大家喜欢!
1、了解什么是CRC
CRC(Cyclic Redundancy Check),即循环冗余校核,是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法。
(1)CRC算法原理
CRC校验本质上是选取一个合适的除数,要进行校验的数据是被除数,然后做模2除法,得到的余数就是CRC校验值。具体原理参见高人CRC说明点击《跳转》。
(2)被除数(即我们要传输的数据)
做为传输数据,在底层都是01传输。那么在CRC计算中,将数据转换成2进制串进行计算,还原数学计算过程。由于网上现成的文章及代码都不能满足数据太长的计算,所以整个代码还原做模运算的除式。
(3)除数(即标准多项式)
多项式,应不同产商的标准不同而不同。产商一般给出如: x3+x2+x0 、x3+x1+x0、x7+x6 +x5 +x2 +1的形式。表示为二进制分别为1101 、1011、11100101。文章来源:https://www.toymoban.com/news/detail-460870.html
注意:在多项式参与计算时。最高位与最低位必为1。按上面得余后,接收数据方在计算时可能会出错,这时可以尝试在多项式最高位加1,来参与计算。(这个坑小编深受其害)文章来源地址https://www.toymoban.com/news/detail-460870.html
2、核心代码如下:点击查看完整代码
package com.cqait.open.crc;
import com.cqait.open.utils.DataConversionUtils;
/**
* CRC(Cyclic Redundancy Check),即循环冗余校核,是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法,主要用来检测或校核数据传输或者保存后可能出现的错误。
* CRC利用除法及余数的原理,实现错误侦测的功能,具有原理清晰、实现简单等优点。
* CRC校验本质上是选取一个合适的除数,要进行校验的数据是被除数,然后做模2除法,得到的余数就是CRC校验值。
*
* @author cqait-open
*/
public class Crc {
/**
* 多项式:原多项式为:11100101 在使用时一般会在最高位添加1。所以是9位了
* X7 +X 6 +X 5 +X 2 +1
*/
public static final String BIN_DXS = "111100101";
/**
* 获取CRC(即循环冗余校验码)
*
* <p>帧校验位(CS)
* CRC(循环冗余校验) 校验 多项式:X 7 +X 6 +X 5 +X 2 +1 (X边上的数据是N次方)
* 多项式与二进制:二进制可表示成多项式的形式,比如二进制1101表示为: x3+x2+x0;1011表示为:x3+x1+x0。
* 所以 11100101 为以上多项式的二进制表示值,即为CRC的除数,控制域+地址域+链路用户数据(应用层)是CRC运算中的被除数 多项式一般省略了最前面的1在计算时加1
* 参照:https://blog.csdn.net/u013073067/article/details/86621770?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86621770-blog-123482805.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-86621770-blog-123482805.pc_relevant_paycolumn_v3&utm_relevant_index=2
* </p>
*
* @param data 二进制字符串(要进行校验的数据)
* @param dxs 多项式二进制串
* @return 返回16进制字典串
*/
public static String getDataCRC(String data, String dxs) {
int dxsInt = Integer.parseInt(dxs, 2);
int dxsLen = dxs.length();
// 对被除数补0
for (int i = 0; i < dxsLen - 1; i++) {
data += "0";
}
int dataLen = data.length();
int startIndex = 0;
int endIndex = dxsLen;
//初始化被除数
String chushu = "";//data.substring(startIndex, endIndex);
// 初始化补尾被除数
String validYuShu = "";
// 是否继续循环
boolean isTrue = true;
// CS值
String binCS = "";
do {
// 被除数 获取本次需要计算的被除数
chushu = validYuShu + data.substring(startIndex, endIndex);
// 转成整形计算
int chushuInt = Integer.parseInt(chushu, 2);
// 异或计算得到整型的余数
int yushuTemp = chushuInt ^ dxsInt;
// 得到2进制余数
String binYushu = DataConversionUtils.toBinString(yushuTemp, false);
// 去掉前面的0
int fisrtIndex = binYushu.indexOf("1");
// 异或后为0
validYuShu = "";
if (fisrtIndex != -1) {
validYuShu = binYushu.substring(fisrtIndex);
}
// 获取余数的长度
int validYuShuLen = validYuShu.length();
// 拼接下次计算的被除数
// 设置下标
startIndex = endIndex;
// 得到需要从被除数上截取的字符长度
int addCount = dxsLen - validYuShuLen;
// 判断被除数有是否有被截取的字符
addCount = endIndex + addCount > dataLen ? dataLen - endIndex : addCount;
endIndex = endIndex + addCount;
String temYUShu = validYuShu + data.substring(startIndex, endIndex);
// 若最后的被除数位数<除数的位数,即此被除数为CS值
if (temYUShu.length() < dxsLen) {
isTrue = false;
binCS = validYuShu + data.substring(startIndex, endIndex);
}
} while (isTrue);
int binCsLen = binCS.length();
// cs补整齐长度为=多项式长度-1
for (int i = 0; i < dxsLen - binCsLen - 1; i++) {
binCS = "0" + binCS;
}
String resHex = DataConversionUtils.toHexString(Integer.parseInt(binCS, 2));
resHex = resHex.length() < 2 ? "0" + resHex : resHex;
//LogUtils.debug(Send427Utils.class, "生成CRC:{}|{}", resHex, binCS);
return resHex;
}
}
ps:小编第一次写文章,有不对的请指出,大家一起探讨。喜欢算法或需要求解代码实现算法的,可以评论区提出,一起解决!小编是一个喜欢算法实现的程序人。
到了这里,关于JAVA获取CRC(即循环冗余校验)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!