計算一個文件的 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,數據檢驗成功!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章