Android開發 - “效驗和”效驗資料在傳輸或儲存過程中是否出錯解析

阿俊学JAVA發表於2024-08-28

校驗和的基本原理

  • 校驗和的基本原理非常簡單,就是把一組資料中的所有位元組(或者其他單位)數值相加,然後得到一個總和,這個總和就是所謂的“校驗和”。在傳輸資料時,傳送方會把資料校驗和一起傳送出去;接收方收到資料後,也會計算一次校驗和,然後與傳送方提供的校驗和進行比較。如果兩個校驗和相同,就認為資料是完整的;如果不同,說明資料傳輸過程中發生了錯誤

簡單的例子

  • 假設有一個資料包,其中包含了以下 4 個位元組的資料:

    10101100
    01101010
    11110000
    00001111
    
  • 如果用一個簡單的校驗和演算法來檢測這些資料是否有錯誤,可以將這 4 個位元組的數值相加,得到一個總和。為了方便理解,把這些二進位制數轉換成十進位制數

    • 10101100 = 172

    • 01101010 = 106

    • 11110000 = 240

    • 00001111 = 15

  • 計算校驗和的值

    校驗和 = 172 + 106 + 240 + 15 = 533
    
    • 這個533就是資料的校驗和傳送方會把這 533 作為資料包的一部分傳送接收方接收方在收到資料包後,會重新計算一次校驗和,並與傳送方校驗和進行比較。如果結果533,則資料沒有出錯;如果不是 533,則表示資料傳輸過程中有錯誤

常見的校驗和型別

簡單加法校驗和

  • 像上面例子一樣,將所有資料數值相加,得到一個總和。計算非常簡單,但無法檢測出所有型別的錯誤

    public class SimpleChecksum {
    
        /**
         * 計算簡單加法校驗和
         * 
         * @param data 位元組陣列
         * @return 校驗和(整數)
         */
        public static int calculateChecksum(byte[] data) {
            int checksum = 0; // 初始化校驗和為0
    
            for (byte b : data) {
                checksum += b; // 將每個位元組的值相加
            }
    
            return checksum & 0xFF; // 返回校驗和的低8位
        }
    
        public static void main(String[] args) {
            // 示例資料
            byte[] data = {(byte) 0xAC, (byte) 0x6A, (byte) 0xF0, (byte) 0x0F};
    
            // 計算校驗和
            int checksum = calculateChecksum(data);
            System.out.printf("Simple Checksum: 0x%02X%n", checksum); // 輸出結果為十六進位制格式
        }
    }
    
    • 遍歷資料陣列,將每個位元組數值相加,結果取低8位

異或校驗和

  • 使用異或(XOR)運算子計算資料校驗和異或校驗和比簡單加法校驗和更能發現某些錯誤型別

    public class XORChecksum {
    
        /**
         * 計算異或校驗和
         * 
         * @param data 位元組陣列
         * @return 校驗和(整數)
         */
        public static int calculateChecksum(byte[] data) {
            int checksum = 0; // 初始化校驗和為0
    
            for (byte b : data) {
                checksum ^= b; // 計算每個位元組的異或校驗和
            }
    
            return checksum;
        }
    
        public static void main(String[] args) {
            // 示例資料
            byte[] data = {(byte) 0xAC, (byte) 0x6A, (byte) 0xF0, (byte) 0x0F};
    
            // 計算校驗和
            int checksum = calculateChecksum(data);
            System.out.printf("XOR Checksum: 0x%02X%n", checksum); // 輸出結果為十六進位制格式
        }
    }
    
    • 遍歷資料陣列,對每個位元組進行異或操作,最終得到一個校驗值

CRC-8 校驗和

  • 簡單加法異或校驗和複雜,也更可靠CRC 使用了一種數學演算法來產生校驗和,能檢測出大多數常見錯誤型別,比如單個錯誤位多個連續錯誤位CRC網路通訊協議常用的校驗方法

    public class CRC8Checksum {
    
        private static final int POLYNOMIAL = 0x07; // CRC-8多項式
    
        /**
         * 計算CRC-8校驗碼
         * 
         * @param data 位元組陣列
         * @return CRC-8的值(整數)
         */
        public static int calculateCRC8(byte[] data) {
            int crc = 0; // 初始化CRC為0
    
            for (byte b : data) {
                crc ^= b; // 當前位元組與CRC進行異或
    
                for (int i = 0; i < 8; i++) { // 對每一位進行處理
                    if ((crc & 0x80) != 0) { // 如果最高位是1
                        crc = (crc << 1) ^ POLYNOMIAL; // 左移1位並與多項式進行異或
                    } else {
                        crc <<= 1; // 僅左移1位
                    }
                    crc &= 0xFF; // 確保CRC值在8位以內
                }
            }
    
            return crc;
        }
    
        public static void main(String[] args) {
            // 示例資料
            byte[] data = {(byte) 0xAC, (byte) 0x6A, (byte) 0xF0, (byte) 0x0F};
    
            // 計算CRC-8
            int crc = calculateCRC8(data);
            System.out.printf("CRC-8: 0x%02X%n", crc); // 輸出結果為十六進位制格式
        }
    }
    
    • 遍歷資料陣列,對每個位元組和已有CRC值進行異或,然後根據CRC多項式進行逐位運算,最終得到一個8位的CRC值

校驗和的優勢和侷限性

  • 優勢:

    • 簡單高效:計算校驗和的演算法通常非常簡單,計算速度快,適合在資源有限的系統中使用

    • 快速錯誤檢測:能夠快速檢測出資料傳輸過程中發生的錯誤

  • 侷限性:

    • 有限的錯誤檢測能力:簡單的校驗和演算法,如簡單加法異或,可能無法檢測出某些型別的錯誤(例如,資料的順序發生變化,或兩個相互抵消的錯誤)
    • 不適用於高安全性需求的場合:對於需要高資料完整性安全性應用場景(例如金融交易、敏感資料傳輸),通常使用更復雜可靠的校驗方法,如 CRCHMAC(基於雜湊的訊息認證碼)

總結

  • 校驗和是一種用於驗證資料完整性檢測資料傳輸或儲存過程中錯誤的簡單而有效的工具。透過簡單的加法異或更復雜的演算法(如 CRC)校驗和能幫助確保資料在傳輸過程中不被篡改或損壞。雖然校驗和並不是最可靠的錯誤檢測方法,但由於其計算效率高實現簡單它在許多應用場景中仍然非常有用

相關文章