c#中的串行端口,数据接收不完整消息

c#中的串行端口,数据接收不完整消息,c#,serial-port,C#,Serial Port,我在搞串口。我面临着一个新问题,即一旦我收到数据,我的数据就不完整。如何检查我的数据是否完整,然后进行处理,如果不完整,则不进行处理 以下是我的数据接收和发送功能: private void Send(byte[] cmd) { bResponse = new byte[0]; Write(cmd); } void comPort_DataReceived(object sender, Seri

我在搞串口。我面临着一个新问题,即一旦我收到数据,我的数据就不完整。如何检查我的数据是否完整,然后进行处理,如果不完整,则不进行处理

以下是我的数据接收和发送功能:

 private void Send(byte[] cmd)
        {
            bResponse = new byte[0];
            Write(cmd);        
        }

 void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int iCount = comPort.BytesToRead;
            byte[] bBuffer = new byte[iCount];
            comPort.Read(bBuffer, 0, iCount)
            if (bBuffer.Length == 1 && bBuffer[0] == ACK)
                Write(new byte[] { ENQ });
            else if (bBuffer.Length == 1 && bBuffer[0] == NAK)
            {
                Debug.WriteLine("Incomplete Message detected!");  
            }
            else
            {
                bResponse = bResponse.Concat(bBuffer).ToArray();
                    rResponse = Decode(bResponse);
                    Write(new byte[] { ACK });
            }
        }

我知道我的数据是在几个包中收到的,我需要等待响应完成,但根据上面的代码我不知道。如何检查数据是否完整以确定是否等待?(注意:收到的响应大小不同。)

没有完整性或数据包大小的内置概念


您必须附加到缓冲区,直到看到您(或其他人)定义为协议规范一部分的可识别的数据包结束模式如果您还没有看到要查找的内容,可能会在一段时间后超时。

旧项目的示例,请注意firstindex,lastindex,您输入一个字符以了解长度,开始/结束字符是预定义的,可以是您选择的任何字符,但请确保不要使用任何常用字符

这适用于tcp/ip,但同样的原理也可用于serialport

    public void ReceiveMessage(IAsyncResult ar) 
    {
        int bytesRead;
        try
        {
            lock (client1.GetStream()) 
            {
                bytesRead = client1.GetStream().EndRead(ar);
            }
            string messageReceived = System.Text.Encoding.ASCII.GetString(data, 0, bytesRead);
            received = messageReceived;
            int firstindex = received.IndexOf((char)2);
            int lastindex = received.IndexOf((char)3);
            if (firstindex > 0 && lastindex > 0)
            {
                string first = received.Substring(firstindex, 1);
                string last = received.Substring(lastindex, 1);
            }
            lock (client1.GetStream())
            {
                client1.GetStream().BeginRead(data, 0, System.Convert.ToInt32(client1.ReceiveBufferSize), ReceiveMessage, null);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
我有一些代码给你。 首先,实现DataReceived事件(正如您已经做的那样)。只有当有数据要处理时才会调用此事件。虽然我不会称之为基于中断的(如“实时功能”),但绝对不是轮询。这很好

第二:调用事件时,可能只有一个字节,但可能有更多字节。要捕获每个数据包,您需要实现一个自定义缓冲区

第三:将一个字节附加到缓冲区后,检查缓冲区是否包含有效数据包。如果是,请进行处理。如果不是:附加另一个。如果没有剩余字节,请等待再次调用事件

在代码中,它如下所示:

const BUFFERLENGTH = 17; // Bytes
byte[] buffer = new byte[BUFFERLENGTH];


private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var port = (SerialPort)sender;
    while (port.BytesToRead > 0)
    {
        var data = (byte)port.ReadByte();
        Read(data);
    }
}

private void Read(byte value)
{
    // Append Byte to buffer
    System.Buffer.BlockCopy(buffer, 1, buffer, 0, BUFFERLENGTH- 1);
    buffer[BUFFERLENGTH - 1] = value;

    // Check for valid Packet
    if (IsValidPacket(buffer))
    {
        // Yeah! Gotcha :-)
        // Now copy your Packet from the Buffer to your struct/whatever
    }
}

private bool IsValidPacket(byte[] buffer)
{
    // Todo: Check whether buffer contains a valid Packet.
    // Some think like:
    // return buffer != null && buffer[0] == 0xF4 && buffer[2] == buffer.length
    throw new NotImplementedException();
}
请注意,我没有“将字节附加到缓冲区”。我丢弃了第一个字节,将每个字节移位一个位置,并在末尾插入新字节。如果找到一个有效的数据包,我可以将它复制到一个结构中。因此,缓冲区大小总是恒定的,并且与一个数据包一样长

这可能不是最快的代码(因为它分别读取每个字节),但对我来说效果很好:-)


哦,如果您想在GUI中显示这些内容,请记住使用Begininvoke()。

服务器错误:有人告诉我使用Interupt,这是什么意思以及如何使用它@PublicAffairm:我不确定在这种情况下这意味着什么。如何在这个概念中附加到缓冲区并检查响应?请定义:您的数据何时完成?你能确定(在程序中)某个数据块是否是一条完整的消息吗?@DasKrümelmonester我会检查其他函数调用解码中的BCC,如果BCC正确,则表示消息的完整性在那里,一旦我收到完整的消息,我会中断其他函数过程?怎么做?用一个布尔值,用一个while循环怎么样?布尔停止=假;虽然(!stop){//Work}不,我用那个,但他们说它很差(轮询方法),所以他们要求我用中断!我真的找不到解决这个问题的办法!好的,你只读了你需要使用startindex和endindex的部分,wy,你不只是关闭组件吗,或者你在说什么样的中断?你的方法对我来说非常新,是的,它不是轮询或中断!然而,我不明白通讯工具在哪里。从我得到的错误,这!我将如何在我当前的应用程序中实现这一点?Comm_Tools是我的静态类,它提供了一些辅助函数。实现您自己的IsValidHeader()函数并定义您自己的headerlength。(或者,如果您愿意,请声明您自己的Comm_Tools类)