golang -- 網絡字節編解碼(1)

在網絡傳輸協議過程當中,封包常見的方式通常是:
①頭標識+數據頭(類型/屬性/數據長度)+數據體+尾標識 -->通常還須要轉義
②固定長度 --> 編解碼方便,浪費寬帶
③經過結尾標識(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)
    }
}
相關文章
相關標籤/搜索