Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在队列中搜索字节<;字节>;提取数据包?_C#_List_Serial Port - Fatal编程技术网

C# 如何在队列中搜索字节<;字节>;提取数据包?

C# 如何在队列中搜索字节<;字节>;提取数据包?,c#,list,serial-port,C#,List,Serial Port,我正在通过COM端口接收数据包。每个数据包以{0xFF,0xFF}开始,以{0xFE,OxFE}结束。所有接收到的字节都在队列中排队,在每个无效端口(object sender,SerialDataReceivedEventArgs e)之后,我正在处理该队列。 若数据包中出现任何0xFF或0xFE,则设备在其后面添加0x00 如何提取每个数据包 如何删除每个内有头字节的数据包中不必要的0x00 关于第一期,我有: void port_DataReceived(object sender, Se

我正在通过COM端口接收数据包。每个数据包以{0xFF,0xFF}开始,以{0xFE,OxFE}结束。所有接收到的字节都在
队列
中排队,在每个
无效端口(object sender,SerialDataReceivedEventArgs e)
之后,我正在处理该队列。 若数据包中出现任何0xFF或0xFE,则设备在其后面添加0x00

  • 如何提取每个数据包
  • 如何删除每个内有头字节的数据包中不必要的0x00
  • 关于第一期,我有:

    void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] data = new byte[port.BytesToRead];
        try
        {
            port.Read(data, 0, data.Length);    
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        data.ToList().ForEach(newByte => receivedData.Enqueue(newByte));
        processData();
    }
    
    private void processData()
    {
        // Determine if we have a "packet" in the queue
        if (Enumerable.SequenceEqual(receivedData.Take(2), new List<byte> { 0xFF, 0xFF }))
        {
            // Beginning of new packet in the front of queue is ready!
            if (Enumerable.SequenceEqual(receivedData.Skip(Math.Max(0, receivedData.Count() - 2)).Take(2), new List<byte> { 0xFE, 0xFE }))
            {
                List<byte> tempPacket = new List<byte>();
                // Whole packet in the queue
                while(receivedData.Count > 0)
                    tempPacket.Add(receivedData.Dequeue());
                tempPacket.TrimExcess();
                Packet pack = new Packet(tempPacket, PacketOrigin.Serial);
            }
        }
    }
    
    void端口\u数据接收(对象发送方,SerialDataReceivedEventArgs e)
    {
    字节[]数据=新字节[port.BytesToRead];
    尝试
    {
    读取端口(数据,0,数据长度);
    }
    捕获(例外情况除外)
    {
    Debug.WriteLine(例如消息);
    }
    ForEach(newByte=>receivedData.Enqueue(newByte));
    processData();
    }
    私有void processData()
    {
    //确定队列中是否有“数据包”
    if(Enumerable.SequenceEqual(receivedData.Take(2),新列表{0xFF,0xFF}))
    {
    //队列前面的新数据包开始准备就绪!
    if(Enumerable.SequenceEqual(receivedData.Skip(Math.Max(0,receivedData.Count()-2)).Take(2),新列表{0xFE,0xFE}))
    {
    List tempPacket=新列表();
    //队列中的整个数据包
    而(receivedData.Count>0)
    Add(receivedData.Dequeue());
    tempPacket.trimposure();
    数据包=新数据包(tempPacket,PacketOrigin.Serial);
    }
    }
    }
    
    我正在尝试删除所有0x00,这些0x00位于任何0xFE和0xFF之后,这些0xFE和0xFF可以在
    队列中找到

    List<byte> unconvertedPacket = new List<byte> { 0xFF, OxFF, 0x00, 0x00,0x4D, 0xFA 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE}
    int index = 0;
    while (index != null)
    {
        unconvertedPacket.RemoveAt(index + 1);
        index = unconvertedPacket.IndexOf(0xFE);
    }
    while (index != null)
    {
        unconvertedPacket.RemoveAt(index + 1);
        index = unconvertedPacket.IndexOf(0xFF);
    }
    
    List unvertedpacket=新列表{0xFF,OxFF,0x00,0x00,0x4D,0xFA 0xFE,0x00,0x01,0x00,0x03,0xFE,0xFE}
    int指数=0;
    while(索引!=null)
    {
    未转换的数据包。移除(索引+1);
    index=unconfertedpacket.IndexOf(0xFE);
    }
    while(索引!=null)
    {
    未转换的数据包。移除(索引+1);
    index=unconfertedpacket.IndexOf(0xFF);
    }
    

    有人有没有其他解决方案/建议?

    尝试以下方法:

    在DataReceived事件处理程序中,保持读取传入数据并将其附加到缓冲区(字节[])

    首先,需要在接收数据的缓冲区中找到开始标记({0xFF,0xFF})。您需要确定缓冲区中此标记的索引

    一旦有了开始索引,就需要继续将传入数据追加到缓冲区,并检查结束标记(0xFE,0xFE)是否已到达。捕获缓冲区内结束标记的索引

    一旦有了开始和结束索引,就可以提取它们之间的数据包。不必担心后面添加的额外0x00字节。您知道起始标记和结束标记的索引及其长度(2)。只需提取它们之间的字节数组

    您需要创建一个搜索算法来满足此目的。针和干草堆都是字节数组(字节[])。为此,您可以使用

    这里是Boyer-Moore算法的一个简单C#实现,它只实现了。如果你还想实现这个功能,请阅读维基百科

    该算法通常用于字符串,但我将其修改为用于字节数组。使用IP摄像头在本地进行测试,以提取接收到的JPEG图像

    有关它的更多信息,请查看维基百科文章。它包含一个完整的Java实现,您可以轻松地将其转换为C

    公共类BoyerMoore
    {
    公共静态int IndexOf(字节[]针,字节[]干草堆)
    {
    如果(针==null | |针.长度==0)
    返回-1;
    int[]charTable=CreateCharTable(指针);
    对于(int i=针的长度-1,j;i
    用法示例:

    var haystack = new byte[] 
      {0xFF, 0xFF, 0x00, 0x00, 0x4D, 0xFA, 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE};
    
    var startIndexOf = BoyerMoore.IndexOf(new byte[] {0xFF, 0xFF}, haystack);
    var endIndexOf = BoyerMoore.IndexOf(new byte[] {0xFE, 0xFE}, haystack);
    
    var packet = new byte[endIndexOf - 2 - startIndexOf];
    for (int i = startIndexOf + 2, j = 0; i < endIndexOf - startIndexOf; i++, j++)
    {
        packet[j] = haystack[i];
    }
    
    var haystack=新字节[]
    {0xFF,0xFF,0x00,0x00,0x4D,0xFA,0xFE,0x00,0x01,0x00,0x03,0xFE,0xFE};
    var startIndexOf=BoyerMoore.IndexOf(新字节[]{0xFF,0xFF},haystack);
    var endIndexOf=BoyerMoore.IndexOf(新字节[]{0xFE,0xFE},haystack);
    var数据包=新字节[endIndexOf-2-startIndexOf];
    对于(inti=startIndexOf+2,j=0;i
    瞧,在这个示例中,数据包字节数组包含9个字节,并且只包含开始和结束标记之间的字节。例如,现在可以触发事件并将数据包作为事件参数传递

    备注:从COM端口接收数据是一个连续事件。你需要一直监视它。继续追加接收到的数据,继续检查开始标记和索引标记,提取包…等等。注意你的缓冲区不会溢出。你需要在那里进行一些内务管理

    希望能有帮助。以连续读取传入数据为例,请查看的实现

    概括地说:

  • 声明一个实例变量来存储接收到的数据(例如_buffer=new byte[4096])
  • 将传入数据附加到DataReceived事件处理程序中的缓冲区
  • 搜索开始标记。如果找到,请记住实例变量中的起始索引
  • 如果你已经知道th的位置
    var haystack = new byte[] 
      {0xFF, 0xFF, 0x00, 0x00, 0x4D, 0xFA, 0xFE, 0x00, 0x01, 0x00, 0x03, 0xFE, 0xFE};
    
    var startIndexOf = BoyerMoore.IndexOf(new byte[] {0xFF, 0xFF}, haystack);
    var endIndexOf = BoyerMoore.IndexOf(new byte[] {0xFE, 0xFE}, haystack);
    
    var packet = new byte[endIndexOf - 2 - startIndexOf];
    for (int i = startIndexOf + 2, j = 0; i < endIndexOf - startIndexOf; i++, j++)
    {
        packet[j] = haystack[i];
    }