以正确的字节序发送UDP数据包 [英] Sending UDP packets in the correct Endianness

查看:253
本文介绍了以正确的字节序发送UDP数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,我在理解网络字节顺序以及通过UDP发送和接收数据的顺序时遇到了麻烦。我正在使用C#



我有一个结构控股:

  message.start_id = 0x7777CCCC; 
message.message _id = 0xBBB67000;
更多数据

消息定义具有 [StructLayout(LayoutKind。顺序)]



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

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

然后我检查字节序:

 如果(BitConverter.IsLittleEndian)
{
Array.Reverse(packet);
}

然后我将其发送

  socket.SendTo(packet,endPoint); 

当我发送此消息时,接收端接收到的消息采用了正确的字节序,但字节顺序相反,所以在Wireshark中,我得到:



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



我期望的时间:7777CCCC BBB67000 ...........其余



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



非常感谢

解决方案


我在理解网络字节顺序以及通过UDP发送和接收数据的顺序时遇到问题


通过UDP发送和接收数据的方式与给套接字的字节顺序完全相同。您只发送或接收字节数组,而UDP根本不对数据报中的字节重新排序。



那么问题是,字节序怎么办? / p>

在许多情况下,答案是无。首先,您今天会遇到的大多数计算机都运行x86架构,并且始终使用little-endian。而且在许多情况下,您无论如何都可以控制两端,因此始终可以坚持使用其中一个。如果您的API可以在字节流之间进行转换,则可以执行此操作,并直接通过UDP套接字发送和接收这些字节。



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



例如,您似乎选择使用big-endian作为协议的字节顺序(我是从一点点代码中推断出这一点的…如果没有一个很好的最小,完整和可验证的示例)。很好原始的BSD套接字API包含网络字节顺序的概念,即big-endian。套接字库包含用于转换的函数,例如从主机顺序到网络顺序再返回的16位整数。



但重要的是要了解字节序会影响每个原始基元级别的数据在您的数据中。您不能一次全部反转整个字节数组,因为如果这样做,那么不仅会改变每个单独基元的字节序,还会改变基元本身的顺序。确实,您在Wireshark跟踪中看到了这一点:数据结构中的两个字段已互换顺序。



要正确处理字节序,您必须检查一下数据结构的每个字段,并分别交换字节。您将不理会字节, short 值(16位)将被交换其字节对, int 值(32位)将反转其四个字节的序列, long 值(64位)将反转八个字节,依此类推



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



要记住的重要事项是考虑到原始数据值使用的实际字节数,字节序总是应用于每个单个原始数据值的级别。


Hi Guys I’m having trouble understanding network byte ordering and the order in which data is sent and received over UDP. I'm using C#

I have a structure holding:

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

the message definition has [StructLayout(LayoutKind.Sequential)]

I first convert the structure to a byte array using:

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

And then I check for endianness:

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

then I send it

socket.SendTo(packet, endPoint);

When I send this the receiving end receives the message with the correct endianness applied but the bytes in reverse sequence, so looking in wireshark I get:

the rest..................BBB67000 7777CCCC

when I'm expecting: 7777CCCC BBB67000 ....................the rest

Is what I'm expecting right or is it normal that the first byte in the structure is the last to arrive?

Many Thanks

解决方案

I’m having trouble understanding network byte ordering and the order in which data is sent and received over UDP

Data is sent and received over UDP in exactly the byte order given to the socket. You only send or receive arrays of bytes and UDP doesn't reorder the bytes within a datagram at all.

So then the question is, what to do about endianness?

Well, in many cases, the answer is "nothing". For one, most computers you'll run into today are running x86 architecture and always use little-endian. And in many scenarios, you have control over both ends anyway and so can always stick with one or the other. If your API has a way to convert things to and from streams of bytes, you can just do that and send and receive those bytes directly with your UDP socket.

But yes, sometimes you need to be able to deal with transmitting data in an endianness that is different from that natively supported on the architecture on which your program is running.

In your particular example, you seem to have chosen to use big-endian as the byte order for your protocol (I'm inferring this from the little bit of code…it's not really possible to know for sure without a good Minimal, Complete, and Verifiable example). Which is fine; the original BSD socket API includes the concept of "network byte order", which is big-endian. The socket library includes functions to convert, e.g. 16-bit integers from "host order" to "network order" and back.

But it's important to understand that the endianness affects your data at the level of each individual primitive in your data. You can't reverse the entire array of bytes all at once, because if you do that will change not just the endianness of each individual primitive, but also the order of the primitives themselves. And sure enough, you see this in your Wireshark trace: the two fields in your data structure have had their order swapped.

To handle endianness properly, you have to go through each field of your data structure and swap the bytes individually. You'll leave bytes alone, short values (16-bit) will have their pair of bytes swapped, int values (32-bit) will have their four-byte sequence reversed, long values (64-bit) will have eight bytes reversed, and so on.

To make matters more complicated, some data structures aren't affected by endianness at all (e.g. UTF8-encoded text), while others have more complex rules (e.g. a Windows GUID/UUID, which is a 128-bit value that is actually defined as a complex data structure, having multiple fields of varying size).

The important thing to remember is that the endianness is always applied at the level of each individual primitive data value, taking into account the actual number of bytes that primitive data value uses.

这篇关于以正确的字节序发送UDP数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆