go語言預設是大端。一般來說網路傳輸的位元組序,可能是大端序或小端序,取決於軟體開始時通訊雙方的協定規定。 TCP/IP協定RFC1700規定使用「大端」字節序為網路字節序,開發的時候需要遵守此規則;而預設golang是使用大端序的。
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
字節序:位元組在電腦中存放時的序列與輸入/輸出時的序列;也指的是存放多位元組資料的位元組(byte)的順序,典型的情況是整數在記憶體中的存放方式和網路傳輸的傳輸順序。
先看下基本概念:
1、大端模式(Big endian):將高序位元組儲存在起始位址(依照從低位址到高位址的順序存放資料的高位元組到低位元組)
2、小端模式(Little endian):將低序位元組儲存在起始位址(按照從低位址到高位址的順序存放據的低位元組到高位元組)
#在電腦領域中,大小端序是跟硬體的體系結構有關的。
舉個栗子:如一個 var a = 0x11223344,對於這個變數的最高位元組為0x11,最低位元組為0x44。假設在記憶體中分配位址如下(位址都是連續的)
... | 0x0001 | 0x0002 | #0x0003 | 0x0004 | ... |
---|
當分別處於大小端模式下的內容存放如下
(1)大端模式儲存(儲存位址為16位元)
##位址資料0x0004(高位址) 0x440x0003 0x330x0002 0x220x0001(低位址) 0x11(2)小端模式儲存(儲存位址為16位元)
位址資料0x0004(高位址) 0x110x0003 0x220x0002 0x33 0x0001(低位址) 0x441、大端序(Big-Endian):或稱為大尾序
#一個型別: int32 的數0X0A0B0C0D的記憶體存放情況 #資料是以8bits為單位
##範例中,最高有效位元是將0x0A儲存在最低的記憶體位址處,接著是0x0B存在後面的位址,類似十六進位位元組從左往右的順序。
資料以16bits為單位
最高的16bit單元0x0A0B儲存在低位
#2、小端序(little-endian):或稱小尾序
資料以8bits為單位 範例中最低有效位元則是0x0D儲存的記憶體位址處,後面依序存放在後面的位址處。資料以16bits為單位
最低的16bit單元0x0C0D儲存在低位元。
3、總結採用大端序的CPU和採用小端序的CPU不僅在位元組上是相反的,在位元位上也是相反的。
例如0x01在記憶體中的儲存
大端序列:記憶體低位元組00000001 記憶體高位元組
大端序:記憶體低位元組00000000 00000000 00000000 00000001 記憶體高位元組
小端序:低位元記憶體低位元記憶體低位記憶體高位元位元
import ( "encoding/binary" "fmt" ) func BigEndian() { // 大端序 // 二进制形式:0000 0000 0000 0000 0001 0002 0003 0004 var testInt int32 = 0x01020304 // 十六进制表示 fmt.Printf("%d use big endian: \n", testInt) var testBytes []byte = make([]byte, 4) binary.BigEndian.PutUint32(testBytes, uint32(testInt)) //大端序模式 fmt.Println("int32 to bytes:", testBytes) convInt := binary.BigEndian.Uint32(testBytes) //大端序模式的字节转为int32 fmt.Printf("bytes to int32: %d\n\n", convInt) } func LittleEndian() { // 小端序 //二进制形式: 0000 0000 0000 0000 0001 0002 0003 0004 var testInt int32 = 0x01020304 // 16进制 fmt.Printf("%d use little endian: \n", testInt) var testBytes []byte = make([]byte, 4) binary.LittleEndian.PutUint32(testBytes, uint32(testInt)) //小端序模式 fmt.Println("int32 to bytes:", testBytes) convInt := binary.LittleEndian.Uint32(testBytes) //小端序模式的字节转换 fmt.Printf("bytes to int32: %d\n\n", convInt) } func main() { BigEndian() LittleEndian() }
16909060 use big endian:
int32 to bytes: [1 2 3 4] ### [0001 0002 0003 0004]
bytes to int32: 16909060
16909060 use little endian:
int32 to bytes: [4 3 2 1] ### [0004 0003 0002 0001]
bytes to int32: 16909060
func (m Message) Encode() []byte { // 编码消息 // 编码metadata将key-value转为key=value&key=value形式 meta := encodeMetadata(m.Metadata) spL := len(m.ServicePath) // 服务长度 smL := len(m.ServiceMethod) // 服务函数 var err error payload := m.Payload // 消息体 if m.CompressType() != None { // 压缩 compressor := Compressors[m.CompressType()] if compressor == nil { // 默认使用None压缩类型 m.SetCompressType(None) } else { payload, err = compressor.Zip(m.Payload) // GZIP压缩 if err != nil { // 压缩失败 不对传输消息进行压缩 m.SetCompressType(None) payload = m.Payload } } } // RPCX数据包 = header + ID + total size + // 服务名及内容: servicePath(size(servicePath) 、len(servicePath)) + // 服务函数及内容:serviceMethod(size(serviceMethod) 、 len(serviceMethod)) + // 元数据及内容: metadata(size(metadata) 、len(metadata)) + // 消息体及内容:payload(size(payload) 、 len(payload)) // 消息长度 = size(servicePath) + len(servicePath) + size(serviceMethod) // + len(serviceMethod) + size(metadata) + len(metadata) // + size(payload) + len(payload) totalL := (4 + spL) + (4 + smL) + (4 + len(meta)) + (4 + len(payload)) // header + dataLen + spLen + sp + smLen + sm // + metaL + meta + payloadLen + payload metaStart := 12 + 4 + (4 + spL) + (4 + smL) // meata开始位置 payLoadStart := metaStart + (4 + len(meta)) // payLoad开始位置 l := 12 + 4 + totalL data := make([]byte, l) copy(data, m.Header[:]) // 拷贝header内容 // 将数据包以大端序模式进行编码 //totalLen binary.BigEndian.PutUint32(data[12:16], uint32(totalL)) // binary.BigEndian.PutUint32(data[16:20], uint32(spL)) copy(data[20:20+spL], util.StringToSliceByte(m.ServicePath)) binary.BigEndian.PutUint32(data[20+spL:24+spL], uint32(smL)) copy(data[24+spL:metaStart], util.StringToSliceByte(m.ServiceMethod)) binary.BigEndian.PutUint32(data[metaStart:metaStart+4], uint32(len(meta))) copy(data[metaStart+4:], meta) binary.BigEndian.PutUint32(data[payLoadStart:payLoadStart+4], uint32(len(payload))) copy(data[payLoadStart+4:], payload) return data}
以上是go語言預設大端還是小端的詳細內容。更多資訊請關注PHP中文網其他相關文章!