2013-02-01 172 views
1

我正在處理Serialport。我面臨一個新問題,即一旦我收到數據,我的數據就不完整。如何檢查我的數據是否完整,然後處理它們,如果沒有,請不要處理它們?c#中的SerialPort,數據接收不完整消息

這裏是我的數據接收和發送我的功能:

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 }); 
      } 
     } 

我知道自己的數據了幾包被接收,我需要等待,直到響應完成,但我不知道基於上面的代碼。我應該如何檢查數據是否完整以確定是否等待? (P.S:收到的響應的大小各不相同。)

+0

請確定:您的數據何時完成?你能確定(在程序中)某個數據塊是否是一個完整的消息嗎? –

+0

@DasKrümelmonster我會在其他函數調用中檢查BCC解碼,如果BCC正確,則表示它的消息完整 – PublicAffair

回答

2

沒有完整性或數據包大小的內置概念。

您必須追加緩衝區,直到您看到您(或其他人)定義爲協議規範一部分的可識別的數據包末尾模式。 - 如果你還沒有看到你正在尋找的東西,那麼可能會過一段時間。

+0

服務器錯誤:有人告訴我使用Interupt,那是什麼意思以及如何使用它? – PublicAffair

+0

@PublicAffair:我不確定這可能意味着什麼。 –

+0

如何追加到緩衝區並檢查這個概念中的響應? – PublicAffair

0

舊項目的例子,注意第一個索引,最後一個索引,你放入一個字符來知道長度,開始/結束字符是預定義的,可以是你選擇的任何字符,只要不要採取任何普通字符

這是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()); 
     } 
    } 
+0

反正有一次,我收到我打斷其他功能過程的完整信息?怎麼做? – PublicAffair

+0

剛剛使用布爾值,並使用while循環呢? 布爾停止=假; while(!stop) { //工作 } –

+0

沒有我使用那個,但他們說它可憐(輪詢方法),所以他們問我使用中斷!我無法找到解決方案! – PublicAffair

0

我對你有一些代碼。 首先,您實現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(); 
} 

請注意,我沒有「字節追加到緩衝區」。我丟棄了第一個字節,將每個字節移動一個位置,並在最後插入新的字節。如果發現有效的數據包,我可以將它複製到一個結構體中。所以緩衝區大小始終是恆定的,並且與一個數據包一樣長。

這可能不是最快的代碼在那裏(因爲它是分開讀取每個字節),但它很適合我:-)

哦,記得使用的BeginInvoke()如果你想顯示的東西在你的GUI中。

+0

你的方法對我來說非常新穎,而且它不是輪詢或中斷!但是我沒有得到comm_Tools的地方。來自即時消息得到錯誤!以及如何將這在我目前? – PublicAffair

+0

Comm_Tools是我的靜態類,它提供了很少的幫助函數。實現你自己的IsValidHeader()函數並定義你自己的頭長。 (或者如果你喜歡,聲明你自己的Comm_Tools類) –