2008-10-20 32 views
52

Trong tài liệu của phần cứng cho phép chúng ta kiểm soát nó qua UDP/IP, tôi thấy đoạn sau:C# nhỏ endian hoặc lớn endian?

Trong giao thức truyền thông này, DWORD là một dữ liệu 4 byte, WORD là một dữ liệu 2 byte, BYTE là một dữ liệu byte đơn. Định dạng lưu trữ là ít endian, cụ thể là 4 byte (32bits) dữ liệu được lưu trữ như: d7-d0, d15-d8, d23-d16, d31-d24; dữ liệu byte kép (16bits) được lưu trữ dưới dạng: d7-d0, d15-d8.

Tôi tự hỏi làm thế nào điều này dịch sang C#? Tôi có phải chuyển đổi nội dung trước khi gửi đi không? Ví dụ, nếu tôi muốn gửi qua một số nguyên 32 bit, hoặc một chuỗi 4 ký tự?

Trả lời

66

Bản thân C# không xác định được độ cuối. Bất cứ khi nào bạn chuyển đổi sang byte, tuy nhiên, bạn đang thực hiện một sự lựa chọn. Lớp BitConverter có trường IsLittleEndian để cho bạn biết nó sẽ hoạt động như thế nào, nhưng nó không đưa ra lựa chọn. Cũng vậy với BinaryReader/BinaryWriter.

Thư viện MiscUtil của tôi có lớp EndianBitConverter cho phép bạn xác định độ dài cuối; có tương đương tương tự cho BinaryReader/Writer. Không có hướng dẫn sử dụng trực tuyến Tôi sợ, nhưng chúng tầm thường :)

(EndianBitConverter cũng có một chức năng không có trong BitConverter bình thường, để thực hiện chuyển đổi tại chỗ trong mảng byte .)

+2

Cũng nên nhớ trong C# có thể sao chép các giá trị trực tiếp, ví dụ: * ptr = giá trị; trong trường hợp này, bạn nên quan tâm đến thứ tự byte của kiến ​​trúc máy tính. – markmnl

10

Re little-endian, câu trả lời ngắn gọn (để tôi cần phải làm gì) là "có thể không, nhưng nó phụ thuộc vào phần cứng của bạn". Bạn có thể kiểm tra với:

bool le = BitConverter.IsLittleEndian; 

Tùy thuộc vào điều này, bạn có thể muốn đảo ngược các phần bộ đệm của mình. Ngoài ra, Jon Skeet có bộ chuyển đổi cụ thể-endian here (tìm EndianBitConverter).

Lưu ý rằng itanium (ví dụ) là người lớn. Hầu hết các Intels đều rất nhỏ.

Re UDP/IP cụ thể ...?

+0

... Có ai sử dụng .net trên Itanium? – SingleNegationElimination

+0

hmm. Những nghiên cứu cơ bản mà tôi vừa làm dường như gợi ý rằng Windows luôn luôn là một người nhỏ bé (Itaniums có thể hỗ trợ hoặc là endianness). Vì vậy, BitConverter.IsLittleEndian có vẻ như nó luôn luôn * sẽ trở lại đúng, trừ khi bạn đang chạy một cái gì đó wierld như Mono trên một Linux lớn-endian trên itanium. Xem http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx – piers7

+0

Một trong các nhận xét cho thấy xna trên xbox có thể là người lớn; Tôi chưa kiểm tra: http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx#426591 –

3

Bạn cần biết về thứ tự byte mạng cũng như CPU ​​cuối cùng.

Thông thường cho các giao thức TCP/UDP, bạn luôn chuyển đổi dữ liệu sang thứ tự byte mạng bằng cách sử dụng hàm htons (và ntohs và các hàm liên quan của chúng).

Thứ tự mạng thông thường là kết thúc lớn, nhưng trong trường hợp này (vì một số lý do!) Các dấu phẩy hơi nhỏ, vì vậy các hàm này không hữu ích lắm. Điều này quan trọng vì bạn không thể chấp nhận các giao thức UDP mà họ đã thực hiện theo bất kỳ tiêu chuẩn nào khác, nó cũng làm cho cuộc sống trở nên khó khăn nếu bạn có kiến ​​trúc lớn như bạn không thể bọc mọi thứ với htons như bạn cần :-(

Tuy nhiên, nếu bạn đang đến từ một kiến ​​trúc intel x86, sau đó bạn đã ít về cuối nhỏ, vì vậy chỉ cần gửi dữ liệu mà không cần chuyển đổi.

41

bạn cũng có thể sử dụng

IPAddress.NetworkToHostOrder(...) 

Đối với short, int hoặc dài.

0

Nếu bạn đang phân tích và hiệu suất là không quan trọng, hãy xem xét mã rất đơn giản này:

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

Tôi đang chơi đùa với các dữ liệu đóng gói trong UDP Multicast và tôi cần một cái gì đó để sắp xếp lại octet uint16 kể từ khi tôi nhận thấy một lỗi trong phần đầu gói (Wireshark), vì vậy tôi thực hiện điều này:

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

trong trường hợp 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; 
    } 

Đây chỉ là để thử nghiệm

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()); 
    } 

từ đó sản lượng được điều này:

0B0A: {0} 
    0A0B: {0} 
    0D0C0B0A: {0} 
    0A0B0C0D: {0} 
Các vấn đề liên quan