什么是最简洁的字节级操作方法?

Gyö*_*sek 1 c# byte bytearray marshalling

我从服务器的源代码中获得了以下C结构,并且有许多类似的结构:

// preprocessing magic: 1-byte alignment

typedef struct AUTH_LOGON_CHALLENGE_C
{
    // 4 byte header
    uint8   cmd;
    uint8   error;      
    uint16  size;       

    // 30 bytes
    uint8   gamename[4];
    uint8   version1;
    uint8   version2;
    uint8   version3;
    uint16  build;
    uint8   platform[4];
    uint8   os[4];
    uint8   country[4];
    uint32  timezone_bias;
    uint32  ip;
    uint8   I_len;

    // I_len bytes
    uint8   I[1];
} sAuthLogonChallenge_C;

// usage (the actual code that will read my packets): 
sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; // where buf is a raw byte array
Run Code Online (Sandbox Code Playgroud)

这些是TCP数据包,我需要实现一些在C#中发送和读取它们的东西.最干净的方法是什么?

我目前的做法涉及到

[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct foo { ... }
Run Code Online (Sandbox Code Playgroud)

还有很多fixed可以读写的语句,但感觉很笨重,而且由于数据包本身不是固定的长度,我觉得使用它并不舒服.此外,它还有很多工作要做.

但是,它确实很好地描述了数据结构,并且协议可能会随着时间而改变,因此这可能是维护的理想选择.

我有什么选择?用C++编写它并使用一些.NET魔法来使用它会更容易吗?

澄清:我还需要处理字节序问题和空填充字符串.

JSB*_*ոգչ 6

我将创建一个本机C#类来表示数据包及其数据(不是尝试匹配有线格式的数据),并BinaryReader在构造函数中传递它.让它从数据流中以适当的块读取数据:

public class LogonChallenge
{
    public LogonChallenge(BinaryReader data)
    {
        // header
        this.Cmd = data.ReadByte();
        this.Error = data.ReadByte();
        this.Size = data.ReadUInt16();

        // etc
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您有多个共享公共标头或其他前导字段的数据包类型,则可以使用继承来避免重复.本BasePacket类可能读取和填充头字段,而LogonChallenge类将继承BasePacket并开始调用基类的构造后读的挑战领域.