在允许我们通过 UDP/IP 控制它的硬件文档中,我发现了以下片段:
在该通信协议中,DWORD 为 4 字节数据,WORD 为 2 字节数据,BYTE 为单字节数据。存储格式为little endian,即4字节(32bits)数据存储为:d7-d0、d15-d8、d23-d16、d31-d24;双字节(16 位)数据存储为:d7-d0、d15-d8。
我想知道这如何转换为 C#?我必须在发送之前转换东西吗?例如,如果我想发送一个 32 位整数或 4 个字符的字符串?
在允许我们通过 UDP/IP 控制它的硬件文档中,我发现了以下片段:
在该通信协议中,DWORD 为 4 字节数据,WORD 为 2 字节数据,BYTE 为单字节数据。存储格式为little endian,即4字节(32bits)数据存储为:d7-d0、d15-d8、d23-d16、d31-d24;双字节(16 位)数据存储为:d7-d0、d15-d8。
我想知道这如何转换为 C#?我必须在发送之前转换东西吗?例如,如果我想发送一个 32 位整数或 4 个字符的字符串?
C# 本身并没有定义字节序。但是,无论何时转换为字节,您都在做出选择。BitConverter类有一个IsLittleEndian字段来告诉您它的行为方式,但它没有提供选择。BinaryReader/BinaryWriter 也是如此。
我的MiscUtil库有一个 EndianBitConverter 类,它允许您定义字节序;BinaryReader/Writer 也有类似的等价物。恐怕没有在线使用指南,但它们很简单:)
(EndianBitConverter 还具有正常 BitConverter 中不存在的一项功能,即在字节数组中进行就地转换。)
你也可以使用
IPAddress.NetworkToHostOrder(...)
简而言之,int 或 long。
Re little-endian,简短的回答(我需要做任何事情)是“可能不是,但这取决于你的硬件”。您可以通过以下方式检查:
bool le = BitConverter.IsLittleEndian;
根据这所说的,您可能想要反转部分缓冲区。或者,Jon Skeet在这里有特定的字节序转换器(查找 EndianBitConverter)。
请注意,安腾(例如)是大端的。大多数英特尔都是小端的。
重新指定 UDP/IP ...?
您需要了解网络字节顺序以及 CPU 字节序。
htons
通常对于 TCP/UDP 通信,您总是使用函数(和ntohs
,以及它们的相关函数)将数据转换为网络字节顺序。
通常网络顺序是大端,但在这种情况下(出于某种原因!)通信是小端,所以这些功能不是很有用。这很重要,因为你不能假设他们实现的 UDP 通信遵循任何其他标准,如果你有一个大端架构,它也会让生活变得困难,因为你不能htons
按照你应该的方式包装所有东西:-(
但是,如果您来自 intel x86 架构,那么您已经是 little-endian,因此只需发送数据而不进行转换。
我正在使用 UDP Multicast 中的打包数据,我需要一些东西来重新排序 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}
如果您正在解析并且性能不重要,请考虑以下非常简单的代码:
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);