校验和(Checksum)介绍、用Java计算校验和、验证校验和

这篇具有很好参考价值的文章主要介绍了校验和(Checksum)介绍、用Java计算校验和、验证校验和。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

介绍

校验和(Checksum)参考文献RFC1071:https://www.rfc-editor.org/rfc/rfc1071.html

计算校验和、验证校验和

发送端计算校验和的步骤

1)待计算校验和的数据的字节数如果偶数,后面不需要补字节;如果字节数是奇数,在后面补一字节(0x00)。(备注:补的全为0的这个字节仅仅是计算校验和使用,并不发送出去)
2)将每两个相邻的字节作为一组,组成一个16位的整数。
3)将组成的16位的整数系列计算1的补码和—就是先求二进制的和,然后再将超过最高有效位的进位(carries)加到结果的最低有效位上。
4)将上边计算的和取1的补码,即二进制中的1变0,0变1,结果就是最终的校验和。
5)校验和字段清零,存入上一步计算出来的校验。

接收端验证校验和的步骤

1)如果接收到的数据(包含校验和字段)是偶数个字节,不需要考虑补一个字节的事情,直接跳到第3步。
2)如果接收到的数据(包含校验和字段)是奇数个字节,在校验和两个字节的前面插入一个字节(0x00),即在纯数据和校验和之间补一字节(0x00)。
3)每两个字节组成一个16位的整数,对这个整数系列计算1的补码和—就是先求二进制的和,然后再将超过最高有效位的进位(carries)加到结果的最低有效位上。
4)如果计算得到的结果各位全部是1(在1的补码中表示-0),那么就表示结果正确。

原理示意

要计算校验和的纯数据是偶数个字节

计算校验和

例如计算0xF6, 0xF7, 0x00, 0x01, 0xF4, 0xF5, 0xF2, 0x03这个字节序列的校验和。
因为要计算校验和的纯数据是偶数个字节,所以不需要考虑补1个字节的事情。
1) F6F7 + 0001 = F6F8
2) F6F8 + F4F5 = 1 EBED, 其中前面的1是超过最高有效位的进位
3) 1 EBED + F203 = 2 DDF0, 其中前面的2是超过最高有效位的进位
4) 将超过最高有效位的进位丢弃,然后将该丢弃的进位加到DDF0的最低有效位上,即DDF0 + 2 = DDF2
5)将DDF2求1的补码,即0变1,1变0,得到最终的校验和为220D,将这个填到校验和字段中。
6)最后发送出去的字节序列是(包含校验和):0xF6, 0xF7, 0x00, 0x01, 0xF4, 0xF5, 0xF2, 0x03, 0x22, 0x0D

验证校验和

此时要验证的字节系列为0xF6, 0xF7, 0x00, 0x01, 0xF4, 0xF5, 0xF2, 0x03, 0x22, 0x0D,其中后面的220D是发送端发送过来的校验和字段的值。
因为接收到的数据(包括校验和)是偶数个字节,所以不需要考虑补1个字节的事情。
1) F6F7 + 0001 = F6F8
2) F6F8 + F4F5 = 1 EBED, 其中前面的1是超过最高有效位的进位
3) 1 EBED + F203 = 2 DDF0 , 其中前面的2是超过最高有效位的进位
4)2 DDF0 + 220D= 2 FFFD, 其中前面的2是超过最高有效位的进位
5) 将超过最高有效位的进位丢弃,然后将该丢弃的进位加到FFFD的最低有效位上,即FFFD+ 2 = FFFF。结果各位全部为1,正确。

要计算校验和的纯数据是奇数个字节

计算校验和

假设计算0xF6, 0xF7, 0x01这个字节系列的校验和。

1)因为要计算校验和的纯数据是奇数个字节,所以要在后面补一个字节0x00,补充后的字节序列是0xF6, 0xF7, 0x01, 0x00。
2)计算上面字节序列的1的补码和:F6F7 + 0100 = F7F7
3)将F7F7取1的补码,即0变1,1变0,得到最终的校验和为0x0808,将这个填到校验和字段中。
4)最后发送出去的字节序列是(包含校验和):0xF6, 0xF7, 0x01, 0x08, 0x08。

验证校验和

假设收到的要验证的字节系列为0xF6, 0xF7, 0x01, 0x08, 0x08,其中后面的0x0808是发送端发送过来的校验和字段的值。

1) 因为接收到的数据(包括校验和)是奇数个字节,所以要在纯数据和校验和之间补一个字节的0x00,补充后的字节序列是0xF6, 0xF7, 0x01, 0x00, 0x08, 0x08。
2) 计算上面字节序列的1的补码和:F6F7 + 0100 + 0808 = FFFF。结果各位全部为1,正确。

Java代码举例

计算校验和、验证校验和的功能类

package com.thb;

/**
 * 该类提供校验和的功能,计算校验和、检查校验和、计算1的补码和
 * @author thb
 *
 */
public class ChecksumUtil {

	/**
	 * 根据输入的字节数组数据计算校验和。校验和就是RFC1071描述的校验和
	 * @param sourceData 输入数据
	 * @return 16比特位的校验和
	 */
	public static short calculateChecksum(byte[] sourceData) {	
		short checksum;	
		
		// 计算1的补码和
		checksum = calculateOnesComplementSum(sourceData);
		// 将1的补码和取反,即0变1,1变0,就是校验和
		checksum = (short)(~checksum);
		return checksum;
	}
	
	/**
	 * 验证校验和
	 * 因为接收到的数据中包含了发送端填写的校验,所以接收端对接收到的数据计算
	 * 1的补码和,如果结果全为1,校验正确;否则,校验错误。
	 * @param receivedData 接收端收到的数据,其中最后两个字节是校验和
	 * @return true:检查成功, false:检查失败
	 */
	public static boolean checkChecksum(byte[] receivedData) {		
		short onesComplementSum;		
		
		if ((receivedData.length % 2) == 0) {
			 // 如果传入的数据是偶数个字节,那么直接计算1的补码和
			onesComplementSum = calculateOnesComplementSum(receivedData);
		} else {
			// 如果传入的数据是奇数个字节,要在数据后面补一个字节0x00,后面再跟两个字节的校验和
			// 构造一个数据数组,偶数个字节
			byte[] data = new byte[receivedData.length + 1];
			// 将原数据(除校验和两个字段外)先拷贝到data中
			System.arraycopy(receivedData, 0, data, 0, receivedData.length - 2);
			// 数据后面最后一个字节填充0x00
			data[data.length - 3] = (byte)0x00;
			// 将校验和两个字节拷贝到data中
			System.arraycopy(receivedData, receivedData.length - 2 , data, data.length - 2, 2);
			// 计算1的补码和
			onesComplementSum = calculateOnesComplementSum(data);
		}		
		
		return onesComplementSum == (short)0xFFFF;
	}
	
	/**
	 * 根据输入的字节数组数据计算16比特位的1的补码和(1's complement sum)。	
	 * 就是将输入数据每两个字节组成一个16比特位的整数,然后将该整数系列二进制相加,
	 * 并经超过最高有效位的进位丢弃,并经该丢弃的进位加到最低有效位上。
	 * @param data 输入数据
	 * @return 16比特位的1的补码和
	 */
	public static short calculateOnesComplementSum(byte[] data) {
		// 考虑到进位,所以中间结果用32比特位的整数存放,高位两个字节存储的是进位
		int middleSum = 0;		
		
		for (int i = 0; i < data.length; i += 2) {			
			if (data.length % 2 == 0) { // 输入数据的总字节数是偶数
				// 将两个相邻的字节组合成一个整数,并和前面的整数和相加
				middleSum += ((0xFF00 & (data[i] << 8)) | (0x00FF & data[i + 1]));
			} else {  // 输入数据的总字节数是奇数
				// 如果已经到了数据的最后一个字节,后面要补一个各bit位全为0的字节
				if (i == (data.length - 1)) {
					middleSum += ((0xFF00 & (data[i] << 8)) | (0x00FF & 0x00));
				} else {
					middleSum += ((0xFF00 & (data[i] << 8)) | (0x00FF & data[i + 1]));
				}
			}
		}		

		// 定义进位变量
		short carries;
		// 将进位取出来
		carries = (short)((middleSum & 0xFFFF0000) >> 16);
		// 因为将进位加到后面两个字节上,可能又产生了进位,所以要用循环判断处理,
		// 直到不产生进位了为止
		while (carries != 0) { 
			// 将sum的前面两个字节清零,准备下面的计算
			middleSum = (middleSum & 0x0000FFFF);
			// 将进位加到后面两个字节上
			middleSum += carries;
			// 将进位再取出来,因为上面相加后可能又产生了进位
			carries = (short)((middleSum & 0xFFFF0000) >> 16);
		}		

		// 将上面计算结果的低端2个字节取出来返回,就是1的补码和
		return (short)(middleSum & 0x0000FFFF);
	}
}

调用场景举例:要计算校验和的纯数据是偶数个字节

package com.thb;

public class Test2 {

	public static void main(String[] args) {
		// 发送端的原始数据
		byte[] sourceData = new byte[] {(byte)0x01, (byte)0x06, 0x00, 0x06, (byte)0x37, (byte)0x02, (byte)0x23, (byte)0x23};	
		short checksum = ChecksumUtil.calculateChecksum(sourceData);
		System.out.println("checksum: 0x" + Integer.toHexString(Short.toUnsignedInt(checksum)));		

		byte[] dstData = new byte[] {(byte)0x01, (byte)0x06, 0x00, 0x06, (byte)0x37, (byte)0x02, (byte)0x23, (byte)0x23, (byte)0xa4, (byte)0xce};
		boolean result = ChecksumUtil.checkChecksum(dstData);
		System.out.println("verify checksum result: " + result);
	}

}

运行输出:

checksum: 0xa4ce
verify checksum result: true

调用场景举例:要计算校验和的纯数据是奇数个字节

package com.thb;

public class Test2 {

	public static void main(String[] args) {
		// 发送端的原始数据	
		byte[] sourceData = new byte[] {(byte)0x01, (byte)0x00, 0x00, 0x00, (byte)0x04, (byte)0x18, (byte)0x28, (byte)0x38, (byte)0x48};		
		short checksum = ChecksumUtil.calculateChecksum(sourceData);
		System.out.println("checksum: 0x" + Integer.toHexString(Short.toUnsignedInt(checksum)));
		
		byte[] dstData = new byte[] {(byte)0x01, (byte)0x00, 0x00, 0x00, (byte)0x04, (byte)0x18, (byte)0x28, (byte)0x38, (byte)0x48, (byte)0x8a, (byte)0xaf};
		boolean result = ChecksumUtil.checkChecksum(dstData);
		System.out.println("verify checksum result: " + result);
	}

}

运行输出:文章来源地址https://www.toymoban.com/news/detail-778586.html

checksum: 0x8aaf
verify checksum result: true

到了这里,关于校验和(Checksum)介绍、用Java计算校验和、验证校验和的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐

    目录 前言 一、根据坐标经纬度计算两点距离(5种方法) 1.方法一 2.方法二 3.方法三 4.方法四 5.方法五 5.1 POM引入第三方依赖 5.2 代码 6.测试结果对比 二、校验经纬度是否在制定区域内 1.判断一个坐标是否在圆形区域内 2.判断一个坐标是否在一个多边形区域内 3.结果 总结   

    2024年02月10日
    浏览(86)
  • 前后端分离java开发图形验证码+谷歌开源Kaptcha使用(Springboot+redis实现图形验证码校验)

    注册 - 登录 - 修改密码 一般需要发送验证码,但是容易被攻击恶意调用。 手机短信轰炸机是批量、循环给手机无限发送各种网站的注册验证码短信的方法。 短信一条5分钱,如果被大盗刷大家自己计算邮箱通知不用钱,但被大盗刷,带宽、连接等都被占用,导致无法正常使用

    2024年01月19日
    浏览(57)
  • Java21 + SpringBoot3集成easy-captcha实现验证码显示和登录校验

    近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。 本项目为前后端分离开发,后端基于 Java21 和 SpringBoot3 开发,后端使用 Spring Security 、 JWT 、 Spr

    2024年01月23日
    浏览(64)
  • swarm节点间通信问题-关闭checksum校验和

    客户有n台redhat虚拟机,构建了一个swarm集群,服务起来后,发现不同节点间的服务,无法互相访问。经运维大佬排查是服务器的checksum校验是开启状态,关闭即可~ ethtool -k 内网网卡名称 | grep checksum 备注:上面的 备注① 和备注② 很重要,是这个脚本的开机启动顺序,如果配

    2024年01月16日
    浏览(39)
  • Java算法_ 验证二叉搜索树(LeetCode_Hot100)

    题目描述: 给你一个二叉树的根节点 ,判断其是否是一个有效的二叉搜索树。root 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 获得更多?算法思路:代码文

    2024年02月12日
    浏览(40)
  • Java【算法 05】通过时间获取8位验证码(每两个小时生成一个)源码分享

    要求是很简单的,每个验证码的有效时间是 2小时 ,这个并不是收到验证码开始计时的,而是每个两小时的时间段使用的是相同的验证码。 将 2个小时处理为相同的值 : 很简单的算法分享。优点: 不需要将生成的验证码缓存。 时间入参,能够重复获取相同的值。

    2024年02月05日
    浏览(35)
  • 二,手机硬件参数介绍和校验算法

    第一章 安卓aosp源码编译环境搭建 第二章 手机硬件参数介绍和校验算法 第三章 修改安卓aosp代码更改硬件参数 第四章 编译定制rom并刷机实现硬改(一) 第五章 编译定制rom并刷机实现硬改(二) 第六章 不root不magisk不xposed lsposed frida原生修改定位 第七章 安卓手机环境检测软件分享

    2024年02月08日
    浏览(34)
  • JAVA用tess4j识别复杂的验证码,自定义字库,计算题验证码,jTessBoxEditor,tess4j,验证码识别

    在爬虫爬取数据的过程中可能会遇到各种验证码,导致爬虫无法继续。本文讲解如果在java中如何使用tess4j识别图片中的文本、自定义模型。 等下需要用到脚本引擎计算表达式 github下载地址: https://github.com/tesseract-ocr/tessdata 常用的语言及其traineddata文件对照表 语言 文件 简体

    2024年02月07日
    浏览(44)
  • checksum的算法和代码实现

    现在在一辆汽车上,有很多控制器,很多控制器之间的通讯需要通过CAN网络,通讯过程中数据的传输尤为重要,因为数据的交互之后往往伴随着相关的硬件会执行指令的请求。在这个过程中,数据的检验是非常有必要的,checksum就是用来校验数据的一致性,主要是输入和输出

    2024年02月14日
    浏览(42)
  • 介绍java中的常见排序算法

    Java中的排序算法主要包括以下几种: 冒泡排序(Bubble Sort) 选择排序(Selection Sort) 插入排序(Insertion Sort) 快速排序(Quick Sort) 归并排序(Merge Sort) 堆排序(Heap Sort) 下面分别进行详细介绍。

    2024年02月08日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包