在網絡傳輸協議過程當中,封包常見的方式通常是:
①頭標識+數據頭(類型/屬性/數據長度)+數據體+尾標識 -->通常還須要轉義
②固定長度 --> 編解碼方便,浪費寬帶
③經過結尾標識(eg.經過base64傳輸,以\0結束) -->編解碼方便,浪費 寬帶 python
下面是golang在編解碼的經常使用手段
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 sliceui
// 這是一個例子,編碼爲">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) } }