以正确的 Endianness 发送 UDP 数据包
Sending UDP packets in the correct 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 .......其余的。
我的期望是正确的还是结构中的第一个字节最后到达是否正常?
I’m having trouble understanding network byte ordering and the order in which data is sent and received over UDP
通过 UDP 发送和接收的数据完全按照给定套接字的字节顺序。您只发送或接收字节数组,而 UDP 根本不会对数据报中的字节进行重新排序。
那么问题来了,字节序怎么办?
嗯,在很多情况下,答案是"nothing"。首先,您今天 运行 进入的大多数计算机都是 运行ning x86 体系结构并且始终使用小端。在许多情况下,您无论如何都可以控制两端,因此始终可以坚持其中之一。如果您的 API 有办法将事物与字节流相互转换,您可以直接使用 UDP 套接字发送和接收这些字节。
但是,是的,有时您需要能够处理以不同于您的程序所在的架构 运行ning 本机支持的字节顺序的字节序传输数据。
在您的特定示例中,您似乎选择了使用大端字节序作为协议的字节顺序(我是从少量代码中推断出来的……如果没有 a good Minimal, Complete, and Verifiable example).哪个好;原始的 BSD 套接字 API 包括 "network byte order" 的概念,这是大端。套接字库包括转换函数,例如从 "host order" 到 "network order" 以及返回的 16 位整数。
但重要的是要了解字节顺序会在数据中的每个原始基元级别影响您的数据。你不能一次反转整个字节数组,因为如果你这样做,不仅会改变每个单独原语的字节顺序,还会改变原语本身的顺序。果然,您在 Wireshark 跟踪中看到了这一点:数据结构中的两个字段已经交换了它们的顺序。
要正确处理字节序,您必须遍历数据结构的每个字段并单独交换字节。您将单独保留字节,short
值(16 位)将交换它们的字节对,int
值(32 位)将反转它们的四字节序列,long
值(64 位)将反转 8 个字节,依此类推。
让事情变得更复杂的是,一些数据结构根本不受字节顺序的影响(例如 UTF8 编码的文本),而另一些则有更复杂的规则(例如 Windows GUID/UUID,这是一个 128 位值,实际上被定义为一个复杂的数据结构,具有多个不同大小的字段)。
要记住的重要一点是,字节顺序始终应用于每个原始数据值的级别,同时考虑到原始数据值使用的实际字节数。
我无法理解网络字节顺序以及通过 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 .......其余的。
我的期望是正确的还是结构中的第一个字节最后到达是否正常?
I’m having trouble understanding network byte ordering and the order in which data is sent and received over UDP
通过 UDP 发送和接收的数据完全按照给定套接字的字节顺序。您只发送或接收字节数组,而 UDP 根本不会对数据报中的字节进行重新排序。
那么问题来了,字节序怎么办?
嗯,在很多情况下,答案是"nothing"。首先,您今天 运行 进入的大多数计算机都是 运行ning x86 体系结构并且始终使用小端。在许多情况下,您无论如何都可以控制两端,因此始终可以坚持其中之一。如果您的 API 有办法将事物与字节流相互转换,您可以直接使用 UDP 套接字发送和接收这些字节。
但是,是的,有时您需要能够处理以不同于您的程序所在的架构 运行ning 本机支持的字节顺序的字节序传输数据。
在您的特定示例中,您似乎选择了使用大端字节序作为协议的字节顺序(我是从少量代码中推断出来的……如果没有 a good Minimal, Complete, and Verifiable example).哪个好;原始的 BSD 套接字 API 包括 "network byte order" 的概念,这是大端。套接字库包括转换函数,例如从 "host order" 到 "network order" 以及返回的 16 位整数。
但重要的是要了解字节顺序会在数据中的每个原始基元级别影响您的数据。你不能一次反转整个字节数组,因为如果你这样做,不仅会改变每个单独原语的字节顺序,还会改变原语本身的顺序。果然,您在 Wireshark 跟踪中看到了这一点:数据结构中的两个字段已经交换了它们的顺序。
要正确处理字节序,您必须遍历数据结构的每个字段并单独交换字节。您将单独保留字节,short
值(16 位)将交换它们的字节对,int
值(32 位)将反转它们的四字节序列,long
值(64 位)将反转 8 个字节,依此类推。
让事情变得更复杂的是,一些数据结构根本不受字节顺序的影响(例如 UTF8 编码的文本),而另一些则有更复杂的规则(例如 Windows GUID/UUID,这是一个 128 位值,实际上被定义为一个复杂的数据结构,具有多个不同大小的字段)。
要记住的重要一点是,字节顺序始终应用于每个原始数据值的级别,同时考虑到原始数据值使用的实际字节数。