通讯协议中的checksum校验和算法(转载)
文章目录1 前言2 具体思路3 checksum的算法实现3.1 checksum83.2 checksum164 linux中的校验和算法5 测试1 前言说到检验和算法,比较熟悉的就是循环冗余算法(CRC),通常由CRC-8,CRC-16,以及CRC-32等,但是在资源相对比较紧张的一些平台上,运行CRC也比较吃力,或者对于需要进行快速校验的场合,所以这里可以使用简单的Checksum算法。2
文章目录
1 前言
2 具体思路
3 checksum的算法实现
3.1 checksum8
3.2 checksum16
4 linux中的校验和算法
5 测试
1 前言
说到检验和算法,比较熟悉的就是循环冗余算法(CRC),通常由CRC-8,CRC-16,以及CRC-32等,但是在资源相对比较紧张的一些平台上,运行CRC也比较吃力,或者对于需要进行快速校验的场合,所以这里可以使用简单的Checksum算法。
2 具体思路
这里以8位的Checksum为例,假设输入一组数据0XFF,0X05,0XC1,0X19;
用16位变量保存数据的累加和;
得到累积和之后,将累加和的高8位和低8位相加;
将累加和进行取反操作;
整体流程如下图所示;
最终结算得到的结果为0x20,下面会有相应的测试。
3 checksum的算法实现
3.1 checksum8
uint8_t m_checksum_08(const uint8_t pdata, uint32_t count)
{
register uint16_t sum = 0;
uint8_t addr = (uint8_t *)pdata;
if(count <= 0){
goto error;
}
// Main summing loop
while(count >= 1)
{
sum = sum + *(uint8_t *) addr;
count --;
(uint8_t *) addr++;
}
// Add left-over byte, if any
if (count > 0)
sum = sum + *((uint8_t *) addr);
// Fold 16-bit sum to 8 bits
while (sum>>8){
sum = (sum & 0xFF) + (sum >> 8);
}
return (uint8_t)(~sum);
error:
return 0;
}
3.2 checksum16
uint16_t m_checksum_16(const uint8_t pdata, uint32_t count)
{
register uint32_t sum = 0;
uint16_t addr = (uint16_t *)pdata;
if(count <= 0){
goto error;
}
// Main summing loop
while(count >= 2)
{
sum = sum + *((uint16_t *) addr);
count = count - 2;
(uint16_t *) addr++;
//addr = addr + 2;
}
if(count == 1){
addr++;
sum = sum + *((uint8_t *) addr);
}
// Add left-over byte, if any
if (count > 0)
sum = sum + *((uint8_t *) addr);
// Fold 32-bit sum to 16 bits
while (sum>>16){
sum = (sum & 0xFFFF) + (sum >> 16);
}
return(~sum);
error:
return 0;
}
4 linux中的校验和算法
下面是Linux中作为IP/TCP/UDP的校验和算法的例程,可以在linux/lib/checksum.c中找到,具体如下所示;
#include <linux/export.h>
#include <net/checksum.h>
#include <asm/byteorder.h>
#ifndef do_csum
static inline unsigned short from32to16(unsigned int x)
{
/* add up 16-bit and 16-bit for 16+c bit /
x = (x & 0xffff) + (x >> 16);
/ add up carry… */
x = (x & 0xffff) + (x >> 16);
return x;
}
static unsigned int do_csum(const unsigned char *buff, int len)
{
int odd;
unsigned int result = 0;
if (len <= 0)
goto out;
odd = 1 & (unsigned long) buff;
if (odd) {
#ifdef __LITTLE_ENDIAN
result += (*buff << 8);
#else
result = *buff;
#endif
len–;
buff++;
}
if (len >= 2) {
if (2 & (unsigned long) buff) {
result += *(unsigned short *) buff;
len -= 2;
buff += 2;
}
if (len >= 4) {
const unsigned char *end = buff + ((unsigned)len & ~3);
unsigned int carry = 0;
do {
unsigned int w = *(unsigned int *) buff;
buff += 4;
result += carry;
result += w;
carry = (w > result);
} while (buff < end);
result += carry;
result = (result & 0xffff) + (result >> 16);
}
if (len & 2) {
result += *(unsigned short *) buff;
buff += 2;
}
}
if (len & 1)
#ifdef __LITTLE_ENDIAN
result += *buff;
#else
result += (*buff << 8);
#endif
result = from32to16(result);
if (odd)
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
out:
return result;
}
#endif
5 测试
下面使用三组数据进行测试,代码如下所示;
uint8_t data01[] = { 0XFF,0X05,0XC1,0X19 };
uint8_t data02[] = { 0X11,0X12,0X12,0X04 };
uint8_t data03[] = { 0X11,0X12,0X12,0X04 };
int main()
{
printf(“test\r\n”);
printf(“data01 is 0x%02x \r\n”,m_checksum_08(data01,sizeof(data01)));
printf(“data02 is 0x%02x \r\n”,m_checksum_08(data02,sizeof(data02)));
printf(“data03 is 0x%02x \r\n”,m_checksum_08(data03,sizeof(data03)));
printf("data01 is 0x%04x \r\n",m_checksum_16(data01,sizeof(data01)));
printf("data02 is 0x%04x \r\n",m_checksum_16(data02,sizeof(data02)));
printf("data03 is 0x%04x \r\n",m_checksum_16(data03,sizeof(data03)));
return 0;
}
更多推荐
所有评论(0)