编组可变大小的数据包

时间:2013-08-14 10:37:37

标签: c# marshalling

这个问题在某种程度上延伸了我之前提出的问题c# using marshalling for packet parsing。 我必须解析一个可变大小的数据包,虽然标题大小是固定的,但其中的数据包可以是不同的大小,并且可能在同一个数据包中存在多于一种类型。

例如,数据包的标题中包含以下字段:

1) username(12 bytes)
2 password(12 bytes)
3) id_number(4 bytes)
4) may be 1 or combination of other data packets of variable size(size can be 12, 16 or 512 bytes)
5) crc(2 bytes)

现在数据包可以跟随

a) data packet type 1
1) size(2 bytes)
2) name(12 bytes)
3) id_number(2 bytes)

b) data packet type 2
1) size(2 bytes)
2) data(24 bytes)
3) id_number(1 byte).

因此可以有type1或type2。两种类型也可能存在。我的问题是如何使用编组来解析这些数据包,或者任何人都可以建议其他方式。 我想补充的另一件事是数据包的第1和第3字段将始终分别是数据包大小(2字节)和数据包ID号(1字节)。数据包的第二个字段可以是任何大小可变的(2,3,13,18,515)。

1 个答案:

答案 0 :(得分:1)

作为替代方案,您可以使用LINQ(假设正在使用ASCII编码):

var packet = new byte[]{
    97, 108, 101, 120, 0, 0, 0, 0, 0, 0, 0, 0, // username
    112, 97, 115, 115, 119, 111, 114, 100, 0, 0, 0, 0, //password
    49, 50, 51, 0, // id_number
    0, 53, 0, 0, 1, // 1st data packet
    0, 54, 1, 2, 5, 2, // 2nd data packet
    49, 0 // crc
};

var username = Encoding.ASCII.GetString(packet.Take(12).ToArray());
var password = Encoding.ASCII.GetString(packet.Skip(12).Take(12).ToArray());
var idNumber = Encoding.ASCII.GetString(packet.Skip(24).Take(4).ToArray());
var data = packet.Skip(28).Take(packet.Length - 30).ToArray();
var crc = Encoding.ASCII.GetString(packet.Skip(packet.Length - 2).ToArray());

var nextDataPackedPos = 0;
var nextDataPackedPos = 0;
var dataPackets = data
    .TakeWhile(b => nextDataPackedPos < data.Length)
    .Zip(data.Skip(nextDataPackedPos), (a, b) =>
    {
        var size = Int32.Parse(
        Encoding.ASCII
            .GetString(data.Skip(nextDataPackedPos).Take(2).ToArray())
            .Trim('\0')
        );
        var result = data.Skip(nextDataPackedPos).Take(size).ToArray();
        nextDataPackedPos += size;
        return result;
    }).ToList();

代码首先将数据部分与数据包字节分开。然后它读取每个数据包的大小,并根据它创建一个包含数据包字节的等大小数组。它会前进到下一个数据包的开头,直到到达数组的末尾。