【轉】go語言的位元組序

來源:互聯網
上載者:User

原文:http://lihaoquan.me/2016/11/5/golang-byteorder.html

這個人的部落格寫的不錯,品質也比較高。 我應該也要有這種精神,這種態度。深入到電腦的世界中去。也是一種快樂。

使用Go開發一個簡單反向 Proxy服務 這篇文章也要研究一下。很好

 

---------------------------------------------------------------------------------------------
go語言的位元組序

go

最近在看nsq的源碼時候,發現它處理message的時候,都會採用位元組序進行資料包的處理,於是我覺得有必要深入瞭解下TCP協議中 位元組序的知識

位元組序(Byte Order)

我們一般把位元組(byte)看作是資料的最小單位。當然,其實一個位元組中還包含8個bit (bit = binary digit)。 在一個32位的CPU中“字長”為32個bit,也就是4個byte。在這樣的CPU中,總是以4位元組對齊的方式來讀取或寫入記憶體, 那麼同樣這4個位元組的資料是以什麼順序儲存在記憶體中的呢?我們下面詳細探討一下。

位元組序包括:大端序和小端序,為什麼要這麼麻煩還要分門別類呢?舉個例子,255用二進位表達就是1111 1111,再加1就是1 0000 0000,多了一個1出來,顯然我們需要再用額外的一個位元組來存放這個1,但是這個1要存放在第一個位元組還是第二個位元組呢?這時候因為人們選擇的不同,就出現了大端序和小端序的差異。

而所謂大位元組序(big endian),便是指其“最高有效位(most significant byte)”落在低地址上的儲存方式。例如像地址a寫入0x0A0B0C0D之後,在記憶體中的資料便是:

而對於小位元組序(little endian)來說就正好相反了,它把“最低有效位(least significant byte)”放在低地址上。例如:

對於我們常用的CPU架構,如Intel,AMD的CPU使用的都是小位元組序,而例如Mac OS以前所使用的Power PC使用的便是大位元組序(不過現在Mac OS也使用Intel的CPU了)。

Go 處理位元組序

Go中處理大小端序的代碼位於 encoding/binary ,包中的全域變數BigEndian用於操作大端序資料,LittleEndian用於操作小端序資料,這兩個變數所對應的資料類型都實行了ByteOrder介面:

type ByteOrder interface {    Uint16([]byte) uint16    Uint32([]byte) uint32    Uint64([]byte) uint64    PutUint16([]byte, uint16)    PutUint32([]byte, uint32)    PutUint64([]byte, uint64)    String() string}

其中,前三個方法用於讀取資料,後三個方法用於寫入資料。

大家可能會注意到,上面的方法操作的都是無符號整型,如果我們要操作有符號整型的時候怎麼辦呢?很簡單,強制轉換就可以了,比如這樣:

func PutInt32(b []byte, v int32) {        binary.BigEndian.PutUint32(b, uint32(v))}

為了深入瞭解它們,我們先寫一個程式觀察下go處理大端序和小端序的方式:

package mainimport (    "encoding/binary"    "fmt"    "unsafe")const INT_SIZE int = int(unsafe.Sizeof(0))//判斷我們系統中的位元組序類型func systemEdian() {    var i int = 0x1    bs := (*[INT_SIZE]byte)(unsafe.Pointer(&i))    if bs[0] == 0 {        fmt.Println("system edian is little endian")    } else {        fmt.Println("system edian is big endian")    }}func testBigEndian() {    // 0000 0000 0000 0000   0000 0001 1111 1111    var testInt int32 = 256    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)    fmt.Printf("bytes to int32: %d\n\n", convInt)}func testLittleEndian() {    // 0000 0000 0000 0000   0000 0001 1111 1111    var testInt int32 = 256    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() {    systemEdian()    fmt.Println("")    testBigEndian()    testLittleEndian()}

執行的結果:

system edian is big endian256 use big endian:int32 to bytes: [0 0 1 0]bytes to int32: 256256 use little endian:int32 to bytes: [0 1 0 0]bytes to int32: 256

總結

為了程式的相容,我們在開發跨伺服器的TCP服務時,每次發送和接受資料都要進行轉換,這樣做的目的是保證代碼在任何電腦上執行時都能達到預期的效果。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.