原文地址:https://blog.csdn.net/ybhjx/article/details/50475440
最近在寫一個短信下發功能,客戶端使用c#和java的短信網關的進行網絡通信。 之前使用java進行開發,一切正常,改用c#無法收到網關應答。 想了半天意識到是不是網絡字節序問題, java默認就是大端字節序,和網絡字節序是一至的,所以不轉換也不會有問題, 而c#在windows平台上是小端字節序。 網絡發送字節流是按大端序發送,也就是從左到右發送,和c#的小端序相反,造成網關不能正常識別協議。 嘗試c#中轉換一下字節序,通信成功。 c#中字節序轉換有兩種方法。 非字串使用 System.BitConverter.GetBytes()方法,先讀入字節數組中,然后再用Array.Reverse()對byte數組反序一下,得到大端序字節數組。 代碼: short x = 6; byte[] a=System.BitConverter.GetBytes(x); //得到小端字節序數組 Array.Reverse(a); //反轉數組轉成大端。
另外c#直接提供了網絡字節序轉換方法。 System.Net.IPAddress.HostToNetworkOrder(本機到網絡轉換) System.Net.IPAddress.NetworkToHostOrder(網絡字節轉成本機) 推薦使用這種方法,簡單有效。 代碼示例: short x = 6; short b = System.Net.IPAddress.HostToNetworkOrder(x); //把x轉成相應的大端字節數 byte[] bb = System.BitConverter.GetBytes(b); //這樣直接取到的就是大端字節序字節數組。
對於字符串型:使用 System.Text.Encoding.Default.GetBytes();直接取字串對應字節數組。 不知道為什么這個方法取到的直接就是大端字節數組。不用轉換。 后來查了一下,關於字串的字節序問題,因為gbk和utf-8都是以單個字節表示數字的,所以不存在字節序問題,在多個不同系統架構都用。對於utf-16,則是以雙字節表示一個整數,所以為會有字節序問題,分大小端unicode。 System.Text.Encoding.Default.GetBytes();在我的簡體中文系統上是以gb2312的編碼,也就是單個字來進行編碼的,所以也不會有字節序問題。 補充:“對於任何字符編碼,編碼單元的順序是由編碼方案指定的,與endian無關。例如GBK的編碼單元是字節,用兩個字節表示一個漢字。這兩個字節的順序是固定的,不受CPU字節序的影響。UTF-16的編碼單元是word(雙字節),word之間的順序是編碼方案指定的,word內部的字節排列才會受到endian的影響。”,所以utf-8也沒有字節序的問題。字節序問題之存在於需要使用兩個字節以上來表示整數。而UTF-8只是一串字節流,不存在字節序問題,不過將這些字節流翻譯成Unicode比其他的傳輸方式復雜。以字節為單位編碼的,無論一個漢字是多少個字節,都無字節序問題。 而剩下的, 就是字符編碼內部的字節序了。比如UTF-16是用兩個字節表示一個字符,但是這兩個字節內部如何排序,系統並不知道,所以必須指定字節序。但是UTF-8由於幾個字節表示並不相同,一定要從那個表示長度的字節開始讀,相當於一開始就知道該從哪里是隊頭隊尾,所以不存在字節序問題。 附上字節序說明:
為什么要注意字節序的問題呢?你可能這么問。當然,如果你寫的程序只在單機環境下面運行,並且不和別人的程序打交道,那么你完全可以忽略字節序的存在。但是,如果你的程序要跟別人的程序產生交互呢?尤其是當你把你在微機上運算的結果運用到計算機群上去的話。在這里我想說說兩種語言。C/C++語言編寫的程序里數據存儲順序是跟編譯平台所在的CPU相關的,而JAVA編寫的程序則唯一采用big endian方式來存儲數據。試想,如果你用C/C++語言在x86平台下編寫的程序跟別人的JAVA程序互通時會產生什么結果?就拿上面的 0x12345678來說,你的程序傳遞給別人的一個數據,將指向0x12345678的指針傳給了JAVA程序,由於JAVA采取big endian方式存儲數據,很自然的它會將你的數據翻譯為0x78563412。什么?竟然變成另外一個數字了?是的,就是這種后果。因此,在你的C程序傳給JAVA程序之前有必要進行字節序的轉換工作。
用文字說明可能比較抽象,下面用圖像加以說明。比如數字0x12345678在兩種不同字節序CPU中的存儲順序如下所示: Big Endian 低地址 高地址 -----------------------------------------> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 12 | 34 | 56 | 78 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Little Endian 低地址 高地址 -----------------------------------------> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 78 | 56 | 34 | 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
上面代碼利用IPAddress.NetworkToHostOrder( )方法實現大、小端轉換。 |