打包解包协议中应用crc32校验和

crc32 介绍

crc32包实现了32位循环冗余校验(CRC-32)的校验和算法;

CRC全称为Cyclic Redundancy Check,循环冗余校验。CRC是一种散列函數(HASH,把任意长度的输入通过散列算法输出散列值, HASH具有单向性,不可逆性),主要用来检测或校验数据传输或者保存后可能出现的错误。 生成的数字在传输或者储存之前计算出来并且附加到数据后面,然后接收方进行检验确定数据是否发生变化。一般循环冗余校验的值都是32位的整数。

尽管CRC在错误检测中非常有用,但CRC并不能可靠地校验数据完整性,这是因为CRC多项式是线性结构; 按照ITU规范标准条件,CRC32比CRC16具有更可靠的验证性,CRC64又会比CRC32更可靠。

crc32 应用打包解包协议

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
    "hash/crc32"
)

// Packet packet message
// | 32 bit length | 16 bit version | 32 bit crc | length - 80 bit info |
type Packet struct {
    length  uint32
    version uint16
    crc32   uint32
    info    []byte
}

// Encode encode message
func (p Packet) Encode() (data []byte, err error) {
    buf := new(bytes.Buffer)
    p.length = uint32(len(p.info) + 10)

    err = binary.Write(buf, binary.LittleEndian, (uint32)(p.length))
    if err != nil {
        return
    }

    err = binary.Write(buf, binary.LittleEndian, (uint16)(p.version))
    if err != nil {
        return
    }

    // 返回使用IEEE多项式计算出的CRC-32校验和
    p.crc32 = crc32.ChecksumIEEE(p.info)
    err = binary.Write(buf, binary.LittleEndian, p.crc32)
    if err != nil {
        return
    }

    err = binary.Write(buf, binary.LittleEndian, p.info)
    if err != nil {
        return
    }

    return buf.Bytes(), nil
}

// DecodeLength decode message length
func (p *Packet) DecodeLength(data []byte) (err error) {
    //p.length = binary.LittleEndian.Uint32(data)
    buf := bytes.NewBuffer(data)

    err = binary.Read(buf, binary.LittleEndian, &(p.length))
    return
}

// Decode decode message
func (p *Packet) Decode(data []byte) (err error) {
    buf := bytes.NewBuffer(data)

    err = binary.Read(buf, binary.LittleEndian, &(p.length))
    if err != nil {
        return
    }

    err = binary.Read(buf, binary.LittleEndian, &(p.version))
    if err != nil {
        return
    }

    err = binary.Read(buf, binary.LittleEndian, &(p.crc32))
    if err != nil {
        return
    }

    p.info = buf.Bytes()

    crc := crc32.ChecksumIEEE(p.info)
    if crc != p.crc32 {
        err = fmt.Errorf("checksum of data failed")
    }

    return
}

参考