以正确的字节顺序发送UDP数据包

时间:2016-03-03 14:09:10

标签: c# udp bytearray endianness

嗨大家我无法理解网络字节排序以及通过UDP发送和接收数据的顺序。我正在使用C#

我有一个结构:

message.start_id         = 0x7777CCCC;
message.message _id      = 0xBBB67000;
     more data

邮件定义有[StructLayout(LayoutKind.Sequential)]

我首先使用以下命令将结构转换为字节数组:

public byte[] StructureToByteArray(object obj)
{ 
    int len = Marshal.SizeOf(obj);
    byte[] arr = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(obj, ptr, true);
    Marshal.Copy(ptr, arr, 0, len);
    Marshal.FreeHGlobal(ptr);
    return arr;
}

然后我检查字节顺序:

if (BitConverter.IsLittleEndian)
{
    Array.Reverse(packet);
}

然后我发送

socket.SendTo(packet, endPoint);

当我发送此消息时,接收端接收到应用了正确字节序的消息,但字节按相反的顺序排列,因此查看wireshark我得到:

其余.................. BBB67000 7777CCCC

当我期待:7777CCCC BBB67000 ....................其余的

结构中的第一个字节是最后一个到达时,我期待的是正确的还是正常的?

非常感谢

1 个答案:

答案 0 :(得分:3)

  

我无法理解网络字节排序以及通过UDP发送和接收数据的顺序

通过UDP以完全按给定套接字的字节顺序发送和接收数据。您只发送或接收字节数组,而UDP根本不对数据报中的字节进行重新排序。

那么问题是,如何处理字节序?

嗯,在很多情况下,答案是"没什么"。首先,您今天遇到的大多数计算机都运行x86架构并始终使用little-endian。在许多情况下,无论如何都可以控制两端,因此可以始终坚持使用其中一种。如果您的API有一种方法可以将字符串转换为字节流,则可以直接使用UDP套接字发送和接收这些字节。

但是,有时候,您需要能够处理以与运行程序所支持的体系结构本身不同的字节序传输数据。

在您的特定示例中,您似乎选择使用big-endian作为协议的字节顺序(我从一点点代码中推断出这一点......它真的不可能知道肯定没有a good Minimal, Complete, and Verifiable example)。哪个好;原始的BSD套接字API包括"网络字节顺序"的概念,这是big-endian。套接字库包括转换的功能,例如,来自"主机顺序"的16位整数到"网络秩序"然后回来。

但重要的是要理解,字节序会影响数据中每个单独基元级别的数据。你不能同时反转整个字节数组,因为如果这样做,不仅会改变每个单独基元的字节顺序,还会改变基元本身的顺序。当然,您可以在Wireshark跟踪中看到这一点:数据结构中的两个字段已经交换了订单。

要正确处理字节顺序,您必须遍历数据结构的每个字段并单独交换字节。您将单独保留字节,short值(16位)将交换它们的字节对,int值(32位)将使其四字节序列反转,{{ 1}}值(64位)将八个字节反转,依此类推。

为了使事情变得更复杂,一些数据结构根本不受字节序的影响(例如UTF8编码的文本),而其他数据结构则有更复杂的规则(例如Windows GUID / UUID,这是128位实际定义为复杂数据结构的值,具有不同大小的多个字段。)

要记住的重要一点是,字节顺序始终应用于每个单独的原始数据值的级别,同时考虑原始数据值使用的实际字节数。