计算一个文件的 16 位效验和

题目与要求

编写一个计算机程序用来计算一个文件的 16 位效验和。最快速的方法是用一个 32 位的 整数来存放这个和。记住要处理进位(例如,超过 16 位的那些位),把它们加到效验和中。

要求:

1)以命令行形式运行:check_sum infile
其中 check_sum 为程序名,infile 为输入数据文件名。
2)输出:数据文件的效验和

附:效验和(checksum)
参见 RFC1071 - Computing the Internet checksum

  • 原理:把要发送的数据看成 16 比特的二进制整数序列,并计算他们的 和。若数据字
    节长度为奇数,则在数据尾部补一个字节的 0 以凑成偶数。
    29
  • 例子:16 位效验和计算,下图表明一个小的字符串的 16 位效验和的计算。
    为了计算效验和,发送计算机把每对字符当成 16 位整数处理并计算效验和。如果效验和大于 16 位,那么把进位一起加到最后的效验和中.

在这里插入图片描述

检验和原理

检验和原理,即为IP数据报首部校验和,其计算采用16位二进制反码求和算法。
在这里插入图片描述
步骤:
将数据报首部按字(16位)进行反码运算求和,获取的和取反码后即为检验和。发送端发送数据报时将检验和带上,接收端接受时,再次计算检验和,若结果为0则保留;否则丢弃该数据报。
在这里插入图片描述

参考代码

public class Main {

    public static void main(String[] args) {
        try {
          if(args == null || args.length != 1 ) {
              System.out.println("使用方式:java class名 文件路径");
          } else if(args.length == 1){
              System.out.println("读取"+args[0]+"...");
              System.out.println("检验码为:"+check_sum(args[0]));
          }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("出现异常,已退出!");
        }
    }

    /**
     * 计算文件校验和
     * @param path 文件路径
     * @return     校验和
     */
    public static String check_sum(String path) throws IOException {
        // 计算总和,
        int sum = 0;
        // 读取文件流
        File file = new File(path);
        FileInputStream inputStream = new FileInputStream(file);
        // 字节数组,2个字节,代表16位
        byte[] b = new byte[2];
        // 读取的字节数
        int n;
        while((n = inputStream.read(b)) != -1) {
            if(n == 1) {
                // 读取字节数为奇数,补齐8个0(1字节)
                sum += b[0] << 8;
            } else {
                // 读取字节数为偶数
                sum += (b[0] << 8) + b[1];
            }
        }
        inputStream.close();
        // 进位处理
        if(sum > 0xffff) {
            sum = (sum / 65536 + sum % 65536);
        }
        // 取反码 java的int占32位,而校验码为16位
        return Integer.toHexString(~sum).substring(4);
    }


}

关于文件读取的问题:这里建议用字节流读取,因为java中的String是2个字节的,也就是16位。而题目这里要求的是两个字组成16位。用字符流读取不仅要进行字节的转换,还容易出错。使用其他编程语言实现也同理,建议使用字节流。

运行

首先在桌面创建一个文本文件:
在这里插入图片描述
然后打开命令行编译运行程序:

在这里插入图片描述

  • java Main中的Main为程序入口的类

检验运算结果

71FC: 0111 0001 1111 1100
取反: 1000 1110 0000 0011
即: 8 e 0 3

模拟客户端接收:
4865+6C6C+6F20+776F+726C+642E+8E03(检验码) = 2FFFD
2FFFD进行反码处理:2FFFD / 0x10000 + 2FFFD % 0x10000 = 0xFFFF
取反:0x0000,即为0,数据检验成功!

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值