从字节缓冲区中提取数据包

Sae*_*ani 6 c# linq arrays extract list

我有一个长度为256的缓冲区,它接收来自蓝牙的字节序列.我需要提取的实际数据包是以字节开头和结尾126.我想使用LINQ在缓冲区中提取最新的数据包.

我现在正在做的是检查最后一个索引,126然后向后计数,直到我到达另一个126.还存在一些缺陷,例如,两个相邻的数据包可能导致两个字节126紧挨着.

这是缓冲区的示例:

126   6 0   5   232 125 93  126 126 69  0 
0   1   0   2   2   34  6   0   5   232 125 
93  126 126 69  0   0   1   0   2   2   34 
6   0   5   232 125 93  126 126 69  0   0 
1   0   2   2   34  6   0   5   232 125 93 
126 126 69  0   0

所以我的信息是:

  • 数据包以字节值126开始和结束
  • 起始索引之后的下一个字节的值为69
  • 在126的结束字节右边的最后3个字节是我知道如何计算的整个数据包的CRC,所以在提取数据包之后我可以检查这个CRC以查看我是否有正确的数据包

所以最后我希望有一个包含正确数据包的数组或列表.例如:

126 69  0  0   1   0   2   2   34  6   0   5   232 125 93 126
Run Code Online (Sandbox Code Playgroud)

你能给我一个从缓冲区中提取这个数据包的快速解决方案吗?

这是我到目前为止所尝试的......它失败了,因为它无法真正返回我正在寻找的正确数据包:

var data = ((byte[])msg.Obj).ToList(); //data is the buffer 

byte del = 126; //delimeter or start/end byte
var lastIndex = data.LastIndexOf(del);
var startIndex = 0;
List<byte> tos = new List<byte>(); //a new list to store the result (packet)    

//try to figure out start index                            
if(data[lastIndex - 1] != del)
{
    for(int i = lastIndex; i > 0; i--)
    {
        if(data[i] == del)
        {
            startIndex = i;
        }
    }

    //add the result in another list
    for(int i = 0; i <= lastIndex - startIndex; i++)
    {
        tos.Add(data[i]);
    }

    string shit = string.Empty;

    foreach (var b in tos)
        shit += (int)b + ", ";

   //print result in  a textbox
    AddTextToLogTextView(shit + "\r\n");
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*zek 3

解决方案

我准备了三种可能的解决方案,从输入缓冲区中取出最后一个数据包:

使用LINQ

public static byte[] GetLastPacketUsingLINQ(byte[] input, byte delimiter)
{
    var part = input.Reverse()
                    .SkipWhile(i => i != delimiter)
                    .SkipWhile(i => i == delimiter)
                    .TakeWhile(i => i != delimiter)
                    .Reverse();

    return (new byte[] { delimiter }).Concat(part).Concat(new byte[] { delimiter }).ToArray();
}
Run Code Online (Sandbox Code Playgroud)

使用string.Split

public static byte[] GetLastPacketUsingString(byte[] input, byte delimiter)
{
    var encoding = System.Text.Encoding.GetEncoding("iso-8859-1");
    string inputString = encoding.GetString(input);
    var parts = inputString.Split(new[] { (char)delimiter }, StringSplitOptions.RemoveEmptyEntries);

    return encoding.GetBytes((char)delimiter + parts[parts.Length - 2] + (char)delimiter);
}
Run Code Online (Sandbox Code Playgroud)

使用while循环和索引器

public static byte[] GetLastPacketUsingIndexers(byte[] input, byte delimiter)
{
    int end = input.Length - 1;
    while (input[end--] != delimiter) ;

    int start = end - 1;
    while (input[start--] != delimiter) ;

    var result = new byte[end - start];
    Array.Copy(input, start + 1, result, 0, result.Length);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

表现

我还进行了一些非常简单的性能测试。结果如下:

LINQ version result:
126 69 0 0 1 0 2 2 34 6 0 5 232 125 93 126

String version result:
126 69 0 0 1 0 2 2 34 6 0 5 232 125 93 126

Indexers version result:
126 69 0 0 1 0 2 2 34 6 0 5 232 125 93 126

LINQ version time: 64ms (106111 ticks)
String version time: 2ms (3422 ticks)
Indexers version time: 1ms (2359 ticks)
Run Code Online (Sandbox Code Playgroud)

结论

正如您所看到的,这里最简单的也是最好的。

您可能认为 LINQ 是所有问题的答案,但有时手动编写更简单的解决方案比使用 LINQ 方法确实更好。