2008-10-20 80 views
52

在硬件的文檔,使我們能夠通過UDP/IP控制它, 我發現下面的片段:C#小端或大端?

在該通信協議,DWORD是一個4個字節的數據,WORD是一個2個字節的數據, BYTE是一個單字節數據。存儲格式爲小端,即4個字節(32位)的數據存儲爲:d7-d0,d15-d8,d23-d16,d31-d24;雙字節(16位)數據存儲爲:d7-d0,d15-d8。

我想知道這是如何轉換爲C#? 在發送之前是否需要轉換內容? 例如,如果我想發送一個32位整數或4個字符的字符串?

回答

66

C#本身沒有定義字節順序。但是,無論何時轉換爲字節,您都在做出選擇。 BitConverter類有一個IsLittleEndian字段告訴你它將如何表現,但它沒有給出選擇。 BinaryReader/BinaryWriter也是如此。我的MiscUtil庫有一個EndianBitConverter類,它允許你定義字節序; BinaryReader/Writer有類似的等價物。沒有在線使用指南恐怕,但他們很平凡:)

(EndianBitConverter也有一塊功能,這是不存在於正常的BitConverter,這是在一個字節數組就地轉換)

10

Re little-endian,簡短的回答(我需要做什麼)是「可能不是,但它取決於你的硬件」。你可以檢查:

bool le = BitConverter.IsLittleEndian; 

根據這說的,你可能想扭轉部分緩衝區。或者,喬恩Skeet具有特定的endian轉換器here(尋找EndianBitConverter)。

請注意,itanium(例如)是big-endian。大多數英特爾都是小端。

重新具體的UDP/IP ...?

+0

...是使用安騰.NET的人? – SingleNegationElimination 2009-03-26 23:09:44

+0

hmm。我剛剛做的基礎研究似乎表明,Windows始終是小端(安騰可以支持任何字節序)。因此,BitConverter.IsLittleEndian看起來像*總是*會返回true,除非您在itanium上的big-endian linux上運行像Mono這樣的Wierld。 請參閱http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx – piers7 2010-01-05 07:55:01

3

您需要了解網絡字節順序以及CPU端位置。

通常對於TCP/UDP通信,您總是使用htons函數(和ntohs及其相關函數)將數據轉換爲網絡字節順序。

通常網絡順序是big-endian,但在這種情況下(出於某種原因!)通信是小端,所以這些功能不是很有用。這很重要,因爲您不能假定他們實施的UDP通信遵循任何其他標準,但如果您擁有大端架構,則您也會生活困難,因爲您無法用htons包裝所有內容,因爲您應該:-(

但是,如果你從一個英特爾x86架構的到來,那麼你已經小尾數,因此只要發送數據,而無需轉換。

41

您還可以使用

IPAddress.NetworkToHostOrder(...) 

對於短,INT或長。

0

如果你分析和性能並不重要,考慮這個非常簡單的代碼:

private static byte[] NetworkToHostOrder (byte[] array, int offset, int length) 
{ 
    return array.Skip (offset).Take (length).Reverse().ToArray(); 
} 

int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0); 
0

我與打包擺弄數據的UDP組播和我需要的東西來重新排序UINT16個字節,因爲我注意到在分組報頭(Wireshark的)的錯誤,所以我提出這樣的:

private UInt16 swapOctetsUInt16(UInt16 toSwap) 
    { 
     Int32 tmp = 0; 
     tmp = toSwap >> 8; 
     tmp = tmp | ((toSwap & 0xff) << 8); 
     return (UInt16) tmp; 
    } 

在UInt32的的情況下,

private UInt32 swapOctetsUInt32(UInt32 toSwap) 
    { 
     UInt32 tmp = 0; 
     tmp = toSwap >> 24; 
     tmp = tmp | ((toSwap & 0xff0000) >> 8); 
     tmp = tmp | ((toSwap & 0xff00) << 8); 
     tmp = tmp | ((toSwap & 0xff) << 24); 
     return tmp; 
    } 

這僅僅是測試

private void testSwap() { 
     UInt16 tmp1 = 0x0a0b; 
     UInt32 tmp2 = 0x0a0b0c0d; 
     SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1)); 
     SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1))); 
     Debug.WriteLine("{0}", shb1.ToString()); 
     Debug.WriteLine("{0}", shb2.ToString()); 
     SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2)); 
     SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2))); 
     Debug.WriteLine("{0}", shb3.ToString()); 
     Debug.WriteLine("{0}", shb4.ToString()); 
    } 

從中輸出是這樣的:

0B0A: {0} 
    0A0B: {0} 
    0D0C0B0A: {0} 
    0A0B0C0D: {0}