怎么计算这个checksum

这个是上次有人发的一个招聘信息里的面试题, 信息详细和网络数据包格式如下, 对于其中的checksum不得其解, 哪位高手能解释一下吗。

     0        4        8      12
     +--------+--------+------+=============+
     |SEQUENCE|CHECKSUM|LENGTH| DATA        | 
     +--------+--------+------+=============+ 

  SEQUENCE
     数据包序号(大端序)
  CHECKSUM (校验和) 
     32位校验和,计算方式如下:首先将序号和数据拼接在一块,然后以32位为块,进行迭代异或操作。
     第一次迭代时,将第一块(数据包序号)与第二块进行异或,第二次迭代时,将第三块与上次迭代的结果进行异或,以此反复。
     如果 LENGTH 不是4的整数倍,需要用 0xAB 填充。
  LENGTH
     数据片段长度(大端序)
  DATA
     长度为 LENGTH 数据片段

自己写的checkSum函数如下, 没有成功, 我可能理解错误:

func checkSum(msg []byte) bool {
    var (
        sum   uint32
        index int = 0
    )
    if len(msg) <= 12 {
        return false
    }
    seqbuf := bytes.NewReader(msg[0:4])
    var seq uint32
    err := binary.Read(seqbuf, binary.BigEndian, &seq)
    if err != nil {
        log.Fatal("binary read error ", err)
    }
        var dataLen uint32
    err := binary.Read(seqbuf, binary.BigEndian, &dataLen)
    if err != nil {
        log.Fatal("binary read error ", err)
    }        
        length := int(dataLen)
    bufReader := bytes.NewReader(msg[4:8])
    var checksum uint32
    err = binary.Read(bufReader, binary.BigEndian, &checksum)
    if err != nil {
        log.Fatal("binary read error ", err)
    }

/*
    if length%4 != 0 {
        msg = bytes.Join([][]byte{msg, []byte{0xAB}}, nil)
    }
    */        
    padLen := 4 - length%4
    for ; padLen > 0; padLen-- {
                msg = append(msg, 0xAB)
    }

    data := bytes.Join([][]byte{msg[0:4], msg[12 : 12+length]}, nil)
    sum = seq ^ uint32(data[index+1])
    index += 2
    length -= 2
    for length > 1 {
        sum ^= uint32(data[index])
        index += 1
        length -= 1
    }
    if length > 0 {
        sum ^= uint32(data[index])
    }
    //sum += (sum >> 16)
    if sum != checksum {
        return false
    }
    return true
}
已邀请:

sheepbao - https://sheepbao.github.io 爱go,爱编程,领域网络开发,流媒体、分布式、网络加速

赞同来自: doit05 kggg

chechsum 校验和在网络传输中用的很多,详细的定义看https://tools.ietf.org/html/rfc1071 按照你给的题目的算法描述,和这个checksum还是有区别的。

func checksum(seq uint32, b []byte) uint32 {
    var (
        sum     uint32
        padByte byte
        padLen  int
    )

    padByte = byte(0xAB)
    sum = seq

    dataLen := len(b)
    remainder := dataLen % 4

    if remainder > 0 {
        padLen = 4 - remainder
    }

    padding := func() []byte {
        pad := make([]byte, 4)
        lastData := b[dataLen-remainder:]

        for i := 4 - padLen; i < 4; i++ {
            pad[i] = padByte
        }

        for i := range lastData {
            pad[i] = lastData[i]
        }

        return pad
    }

    if dataLen < 4 {
        sum += binary.BigEndian.Uint32(padding())
        return sum
    }

    for i := 0; i+4 < dataLen; i += 4 {
        sum ^= binary.BigEndian.Uint32(b[i:])
    }

    if padLen != 0 {
        sum ^= binary.BigEndian.Uint32(padding())
    }

    return sum
}

尽量避免内存分配,msg = append(msg, 0xAB) append会分配内存,seq不需要转化成byte slice,因为最后是求sum,把data转uint32即可。 原来你用padLen := 4 - length%4是不对的,如果length长度是4的倍数,你会导致padLen=4

morya

赞同来自: heramerom

其它没看,但 padding 我觉得不对。 要求padding到4的整数倍,你只是padding了一个

if length%4 != 0 {
    msg = bytes.Join([][]byte{msg, []byte{0xAB}}, nil)
}

用下面这个挫循环整一下

padLen := 4 - len(msg) %4
for ; padLen > 0; padLen-- {
    msg = append(msg, 0xAB)
}

感觉剩下的就是一个死循环

for length > 0 {
    binary.Read(r, binary.BigEndian, &tmp)
    seq = seq ^ tmp
    length -= 4
}

kggg

赞同来自:

不太明白下面这段for, tmp 一直读取是同样的数据吧?

for length > 0 {
    binary.Read(r, binary.BigEndian, &tmp)
    seq = seq ^ tmp
    length -= 4
}

要回复问题请先登录注册