在网络传输协议过程中,封包常见的方式一般是:
①头标识+数据头(类型/属性/数据长度)+数据体+尾标识 -->一般还需要转义
②固定长度 --> 编解码方便,浪费宽带
③通过结尾标识(eg.通过base64传输,以\0结束) -->编解码方便,浪费 宽带
下面是golang在编解码的常用手段
解码
首先需要把[]byte的ascii串转化为uint8,uint16,uint32,uint64等 (分别对应python的B,H,I,Q).特别要注意大端和小端对齐方式(python大端">",小端"<", 这里也用它们的ascii吧)
// 这是一个例子, 解码出 ">HHI"
func unpack(data []byte, edian byte) (uint16, uint16, uint32, []byte) {
dataType := ToUInt16(data[0:2], edian)
dataAttr := ToUInt16(data[2:4], edian)
dataLen := ToUInt32(data[4:8], edian)
extra := data[8:]
return dataType, dataAttr, dataLen, extra
}
func ToUInt8(buf []byte, edian byte) uint8 {
// len(buf) == 1 -->B
t := uint8(buf[0])
return t
}
func ToUInt16(buf []byte, edian byte) uint16 {
// len(buf) == 2 -->H
t := uint16(buf[0])
if edian == 62 { // ">"
t = t<<8 | uint16(buf[1])
} else if edian == 60 { // "<"
t = t | uint16(buf[1])<<8
}
return t
}
func ToUInt32(buf []byte, edian byte) uint32 {
// len(buf) == 4 -->I
t := uint32(buf[0])
if edian == 62 {
t = t << 24
t = t | uint32(buf[1])<<16
t = t | uint32(buf[2])<<8
t = t | uint32(buf[3])
} else if edian == 60 {
t = t | uint32(buf[1])<<8
t = t | uint32(buf[2])<<16
t = t | uint32(buf[3])<<24
}
return t
}
func ToUInt64(buf []byte, edian byte) uint64 {
//len(buf) == 8 -->Q
t := uint64(buf[0])
if edian == 62 {
t = t << 56
t = t | uint64(buf[1])<<48
t = t | uint64(buf[2])<<40
t = t | uint64(buf[3])<<32
t = t | uint64(buf[4])<<24
t = t | uint64(buf[5])<<16
t = t | uint64(buf[6])<<8
t = t | uint64(buf[7])
} else if edian == 60 {
t = t | uint64(buf[1])<<8
t = t | uint64(buf[2])<<16
t = t | uint64(buf[3])<<24
t = t | uint64(buf[4])<<32
t = t | uint64(buf[5])<<40
t = t | uint64(buf[6])<<48
t = t | uint64(buf[7])<<56
}
return t
}
编码
解码的逆过程,把uint8,uint16,uint32转化为[]byte -->ascii slice
// 这是一个例子,编码为">HHI"
func pack(dataType uint16, dataAttr uint16, dataLen uint32) []byte {
buf := make([]byte, 8)
PutUInt16(dataType, buf[0:2], 62)
PutUInt16(dataAttr, buf[2:4], 62)
PutUInt32(dataLen, buf[4:8], 62)
//buf = bufType + bufAttr + bufLen
return buf
}
func PutUInt8(num uint8, buf []byte, edian byte) {
// len(buf) == 1
buf[0] = byte(num)
}
func PutUInt16(num uint16, buf []byte, edian byte) {
// len(buf) == 2
buf[0] = byte(num >> 8)
buf[1] = byte(num)
if edian == 62 { // ">"
} else if edian == 60 { // "<"
buf[0] ^= buf[1]
buf[1] ^= buf[0]
buf[0] ^= buf[1]
}
}
func PutUInt32(num uint32, buf []byte, edian byte) {
// len(buf) == 4
buf[0] = byte(num >> 24)
buf[1] = byte(num >> 16)
buf[2] = byte(num >> 8)
buf[3] = byte(num)
if edian == 62 {
} else if edian == 60 {
buf[0] ^= buf[3]
buf[3] ^= buf[0]
buf[0] ^= buf[3]
buf[1] ^= buf[2]
buf[2] ^= buf[1]
buf[1] ^= buf[2]
}
}
func PutUInt64(num uint64, buf []byte, edian byte) {
// len(buf) == 8
if edian == 62 {
buf[0] = byte(num >> 56)
buf[1] = byte(num >> 48)
buf[2] = byte(num >> 40)
buf[3] = byte(num >> 32)
buf[4] = byte(num >> 24)
buf[5] = byte(num >> 16)
buf[6] = byte(num >> 8)
buf[7] = byte(num)
} else if edian == 60 {
buf[0] = byte(num)
buf[1] = byte(num >> 8)
buf[2] = byte(num >> 16)
buf[3] = byte(num >> 24)
buf[4] = byte(num >> 32)
buf[5] = byte(num >> 40)
buf[6] = byte(num >> 48)
buf[7] = byte(num >> 56)
}
}