在.Net中表示位和它们的序列化

时间:2012-10-30 22:33:40

标签: c# serialization deserialization ntp osi

我正在练习实现一些基本的第7层协议,但我不确定在.Net框架中对位进行串行化和反序列化的最佳方法。

根据MSDN Data Type Summary,没有位数据类型。我不知道如何创建这样的数据类型,或者即使它是可能的,所以我不得不对字节/字节数组进行序列化/反序列化。

从NTP数据包的顶部给出以下示例:

     0-1         LeapIndicator (LI)      2 bits
     2-4         VersionNumber (VN)      3 bits
     5-7         Mode                    3 bits
     8-15        Stratum                 8 bits

我想编码为2个字节,所以我可以通过套接字发送。

另外,我目前正在使用整数来表示枚举中的位,是否可以使用位/十六进制或比int更好的东西?例如,模式枚举定义如下:

public enum Mode
{
    /*
     +-------+--------------------------+
     | Value | Meaning                  |
     +-------+--------------------------+
     | 0     | reserved                 |
     | 1     | symmetric active         |
     | 2     | symmetric passive        |
     | 3     | client                   |
     | 4     | server                   |
     | 5     | broadcast                |
     | 6     | NTP control message      |
     | 7     | reserved for private use |
     +-------+--------------------------+
     */

    Resevered = 0,
    SymmetricActive = 1,
    SymmetricPassive = 2,
    Client = 3,
    Server = 4,
    Broadcast = 5,
    ControlMessage = 6,
    PrivateUse = 7
}

备注:此项目的代码最终将是开源的,请记住,如果您回答。如果您不希望共享代码,请说:)链接将在代码中放回到此问题。

提前致谢:)

更新:如果有人想知道NTP数据包结构是什么样的,可以直接从RFC 5905, page 18

获取
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |LI | VN  |Mode |    Stratum     |     Poll      |  Precision   |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                         Root Delay                            |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                         Root Dispersion                       |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                          Reference ID                         |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        +                     Reference Timestamp (64)                  +
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        +                      Origin Timestamp (64)                    +
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        +                      Receive Timestamp (64)                   +
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        +                      Transmit Timestamp (64)                  +
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        .                                                               .
        .                    Extension Field 1 (variable)               .
        .                                                               .
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        .                                                               .
        .                    Extension Field 2 (variable)               .
        .                                                               .
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                          Key Identifier                       |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                                                               |
        |                            dgst (128)                         |
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

5 个答案:

答案 0 :(得分:3)

我认为我根本不会使用枚举。我可能会创建一个表示数据包标头的结构,将数据存储在ushort(16位)中:

public struct NtpHeader
{
    private readonly ushort bits;

    // Creates a header from a portion of a byte array, e.g
    // given a complete packet and the index within it
    public NtpHeader(byte[] data, int index)
    {
        bits = (ushort) (data[index] + (data[index] << 8));
    }

    public NtpHeader(int leapIndicator, int versionNumber,
                     int mode, int stratum)
    {
        // TODO: Validation
        bits = (ushort) (leapIndicator |
                         (versionNumber << 2) |
                         (mode << 5) |
                         (stratum << 8));
    }

    public int LeapIndicator { get { return bits & 3; } }

    public int VersionNumber { get { return (bits >> 2) & 7; } }

    public int Mode { get { return (bits >> 5) & 7; } }

    public int Stratum { get { return bits >> 8; } }
}

你会想要检查一下 - 目前还不清楚RFC中是否真正表示了哪种位排列。如果您有具有预期值的样本包,那将使事情更加清晰。

答案 1 :(得分:1)

仅供参考,有一个结构代表.NET,System.Boolean。正如Marc所提到的,协议是偶数字节,所以你可以使用int(每个int保存32位),或者使用bitmask样式的枚举。无论哪种方式,您都可以使用System.BitConverter的静态方法进行字节数组的转换。

答案 2 :(得分:1)

您是否考虑过使用Flags属性?它允许您将枚举类型值视为位而不是整数:  http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx

答案 3 :(得分:1)

c#中枚举的最小类型是byte(其他类型的可用解释如下http://msdn.microsoft.com/en-us/library/sbbt4032.aspx)。 定义byte类型的枚举:

enum Name:byte{}
在你的例子中

public enum Mode:byte
{
    /*
     +-------+--------------------------+
     | Value | Meaning                  |
     +-------+--------------------------+
     | 0     | reserved                 |
     | 1     | symmetric active         |
     | 2     | symmetric passive        |
     | 3     | client                   |
     | 4     | server                   |
     | 5     | broadcast                |
     | 6     | NTP control message      |
     | 7     | reserved for private use |
     +-------+--------------------------+
     */

    Resevered = 0,
    SymmetricActive = 1,
    SymmetricPassive = 2,
    Client = 3,
    Server = 4,
    Broadcast = 5,
    ControlMessage = 6,
    PrivateUse = 7
}

如果我们希望节省空间但可读性较差,我们可以看到sizeof(LeapIndicator)+ sizeof(VersionNumber)+ sizeof(Mode)= 8 bits = 1 byte。 并且sizeof(Sratum)= 8位= 1字节。

答案 4 :(得分:1)

序列化:要将数据包字段放入结果中,只需将2(左移)乘以适当的位数,然后将OR与累积结果相乘。

反序列化:要从结果中提取数据包字段,只需使用AND位掩码然后除以2(右移)适当的位数。