0

いくつかの基本的なレイヤー 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 を使用しています。たとえば、mode enum は次のように定義されます。

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
}

補足: このプロジェクトのコードは最終的にオープン ソース化される予定です。コードの共有を望まない場合は、次のように言ってください:) この質問に戻るリンクがコードに配置されます。

前もって感謝します :)

更新: RFC 5905から直接取得した、NTP パケット構造がどのように見えるか疑問に思っている人のために、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)                         |
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4

5 に答える 5

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で実際にどのビット配置が表されているかはすぐにはわかりません。期待値を含むサンプル パケットがあれば、より明確になります。

于 2012-11-09T07:01:53.580 に答える
1

シリアル化:パケットフィールドを結果に入れるには、2(左シフト)に適切なビット数を掛けてから、これまでの累積結果とORします。

デシリアライズ:結果からパケットフィールドを抽出するには、ANDビットマスクを使用してから、適切なビット数で2(右シフト)で除算します。

于 2012-11-08T17:52:49.103 に答える
1

Flags 属性の使用を検討しましたか? 列挙型の値を int ではなくビットとして扱うことができます: http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx

于 2012-11-06T02:25:50.883 に答える
1

参考までに、.NET でビットを表す構造体がありますSystem.Boolean。Marc が述べたように、プロトコルは偶数バイトであるため、int (各 int は 32 ビットを保持) を使用するか、ビットマスク スタイルで列挙型を使用できます。どちらの方法でも、System.BitConverterの静的メソッドを使用して、バイト配列との間で変換を行うことができます。

于 2012-11-05T23:33:10.150 に答える
1

C# の列挙型の最小の型は byte です (使用可能な他の型については、http://msdn.microsoft.com/en-us/library/sbbt4032.aspxで説明されています)。バイト型の列挙型を定義します。

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 ビット = 1 バイトであることがわかります。また、sizeof(Sratum) = 8 ビット = 1 バイトです。

于 2012-11-08T07:26:05.593 に答える