CRC(Cyclic Redundancy Check,循环冗余校验)几乎存在于每一次数据传输和存储背后:以太网帧、USB 传输、ZIP/PNG 文件格式、Modbus 工业协议……它要解决的问题很朴素:数据在传输或存储过程中有没有出错。
数据在传输(网线、无线信号)或存储(硬盘、闪存)过程中,可能因为噪声、干扰、硬件故障产生位翻转(0 变 1 或 1 变 0)。CRC 的作用是:发送方按数据算出一个"校验值"附在末尾,接收方收到后重新计算一次,两次结果不一致就说明数据在路上出错了,需要重传或报错。
它不负责纠错(不知道错在哪一位),只负责检测——这也是为什么叫"校验"而不是"纠错"。
CRC 的数学基础是二进制多项式除法。可以类比成小学学的"除法验证":把数据看成一个大二进制数,除以一个固定的"生成多项式",余数就是 CRC 值。
用一个简化的例子理解(真实 CRC 用异或代替减法,但逻辑相通):
数据:110101
生成多项式(简化为4位):1011
用异或做"除法":
110101
1011
----
010001
1011
----
001101
1011
----
00110 ← 这就是余数(简化版 CRC 值)
真实的 CRC16/32 用的生成多项式经过精心挑选(比如 CRC-32 用 0x04C11DB7),能保证"绝大多数常见的位错误模式"都会导致余数变化,从而被检测出来。
| CRC16 | CRC32 | |
|---|---|---|
| 校验位长度 | 16 位 | 32 位 |
| 检测能力 | 较弱,适合短数据 | 更强,能检测更长数据里的错误 |
| 典型场景 | Modbus 工业协议、老式通信协议 | ZIP/PNG/以太网帧、git 对象校验 |
| 计算开销 | 略低 | 略高,但现代硬件差异可忽略 |
简单说:数据量小、协议历史悠久用 CRC16;现代通用场景基本都用 CRC32。两者不能互相验证,必须用同一种算法。
CRC 常被拿来和 MD5/SHA 这类哈希算法比较,但它们的设计目的完全不同:
| CRC | MD5/SHA 等密码学哈希 | |
|---|---|---|
| 设计目的 | 检测随机的传输/存储错误 | 抵抗故意的恶意篡改 |
| 抗碰撞设计 | 没有,故意构造两个 CRC 相同的数据非常容易 | 设计上要求极难构造碰撞 |
| 计算速度 | 非常快,常有硬件指令加速(如 CRC32C) | 较慢 |
| 能不能用于安全场景 | 不能,几毫秒就能伪造 | MD5/SHA1 已不安全,SHA-256 等仍安全 |
一句话:CRC 防的是"意外出错",哈希算法(用对的话)防的是"有人故意搞破坏"。如果场景涉及安全性(比如校验一个文件是否被恶意篡改),必须用密码学哈希,CRC 完全不够用。
// Node.js 内置 zlib 提供 CRC32
const zlib = require('zlib');
const buf = Buffer.from('hello world');
console.log(zlib.crc32(buf).toString(16));