在C#中使用字节数组

Mat*_*vis 13 .net c# networking bytearray .net-3.5

我有一个字节数组,代表一个完整的TCP/IP数据包.为了澄清,字节数组的排序如下:

(IP标头 - 20字节)(TCP标头 - 20字节)(有效负载 - X字节)

我有一个Parse接受字节数组并返回一个TCPHeader对象的函数.它看起来像这样:

TCPHeader Parse( byte[] buffer );
Run Code Online (Sandbox Code Playgroud)

给定原始字节数组,这是我现在调用此函数的方式.

byte[] tcpbuffer = new byte[ 20 ];
System.Buffer.BlockCopy( packet, 20, tcpbuffer, 0, 20 );
TCPHeader tcp = Parse( tcpbuffer );
Run Code Online (Sandbox Code Playgroud)

有没有一种方便的方法可以将TCP字节数组(即完整TCP/IP数据包的字节20-39)传递给Parse函数,而无需先将其提取到新的字节数组?

在C++中,我可以执行以下操作:

TCPHeader tcp = Parse( &packet[ 20 ] );
Run Code Online (Sandbox Code Playgroud)

C#中有类似的东西吗?我想尽可能避免临时字节数组的创建和后续垃圾收集.

Spo*_*odi 24

您可以在.NET框架中看到并且我建议在此处使用的常见做法是指定偏移量和长度.因此,使您的Parse函数也接受传递的数组中的偏移量,以及要使用的元素数.

当然,同样的规则也适用于传递类似C++的指针 - 不应修改数组,否则如果您不确定何时将使用数据,则可能导致未定义的行为.但是,如果您不再修改数组,这没有问题.


cas*_*One 22

ArraySegment<byte>在这种情况下我会通过.

您可以将Parse方法更改为:

// Changed TCPHeader to TcpHeader to adhere to public naming conventions.
TcpHeader Parse(ArraySegment<byte> buffer)
Run Code Online (Sandbox Code Playgroud)

然后你会改变对此的调用:

// Create the array segment.
ArraySegment<byte> seg = new ArraySegment<byte>(packet, 20, 20);

// Call parse.
TcpHeader header = Parse(seg);
Run Code Online (Sandbox Code Playgroud)

使用ArraySegment<T>不会复制数组,它将在构造函数中为您进行边界检查(这样就不会指定不正确的边界).然后你改变你的Parse方法来使用段中指定的边界,你应该没问题.

您甚至可以创建一个方便的重载,它将接受完整的字节数组:

// Accepts full array.
TcpHeader Parse(byte[] buffer)
{
    // Call the overload.
    return Parse(new ArraySegment<byte>(buffer));
}

// Changed TCPHeader to TcpHeader to adhere to public naming conventions.
TcpHeader Parse(ArraySegment<byte> buffer)
Run Code Online (Sandbox Code Playgroud)