2016-09-05 63 views
2

請求的行爲:我希望聽到提議的通用解決方案,用於暫停調用線程,直到在Stream/SerialPort上接收到特定緩衝區爲止。目前,我不關心超時等,但我需要強大的東西。WaitFor() - 如何等待Steam/SerialPort上的特定緩衝區到達?

嘗試的方法:

Class myClass 
    { 
     private SerialPort _port; //Assume configured and connected. 

     public void WaitFor(byte[] buffer) 
     {    
      int bufferLength = buffer.Length; 
      byte[] comparisonBuffer = new byte[bufferLength]; 

      while(true) 
      { 
       if(_port.BytesToRead >= bufferLength) 
       { 
        _port.Read(comparisonBuffer, 0, bufferLength); 
        if (comparisonBuffer.SequenceEqual(buffer)) { return; } 
       } 
      } 
     } 
    { 

我有一個合理的成功量與此但它只是有一個「哈克」的感覺。它經常給我帶來麻煩。我相信這是由於我無法保證在預期的數據包之前或之後沒有收到其他數據,所以自然這種方法最終可能會讀出流不同步。在這種情況下,我不想丟失前導/尾隨數據,但該方法應該釋放線程。

我需要在程序上實現,所以事件驅動的方法對我來說不會真正起作用。在通用意義上,我希望能夠實現爲;

Do thing; 
    WaitFor(mybuffer); 
    Do other thing; 

回答

0

你認爲這個解決方案是什麼?

public override byte[] WaitFor(byte[] buffer, int timeout) 
{ 
    // List to stack stream into 
    List<byte> stack = new List<byte>(); 
    // Index of first comparison byte 
    int index = 0; 
    // Index of last comparison byte 
    int upperBound = buffer.Length - 1; 
    // Timeout Manager 
    Stopwatch Sw = new Stopwatch(); 

    Sw.Start(); 
    while (Sw.Elapsed.Seconds <= timeout) 
    { 
     // Read off the last byte receievd and add to the stack 
     stack.Add((byte)_port.ReadByte()); 

     // If my stack contains enough bytes to compare to the buffer 
     if (stack.Count > upperBound) 
     { 
      // If my first comparison byte matches my first buffer byte 
      if (stack[index] == buffer[0]) 
      { 
       // Extract the comparison block to array 
       byte[] compBuffer = stack.GetRange(index,upperBound +1).ToArray(); 

       // If the comparison matches, break and return the redundent bytes should I wish to handle them. 
       if ((compBuffer.SequenceEqual(buffer) && (index-1 > 0))) { return stack.GetRange(0, index - 1).ToArray(); } 
       // If there were no redundent bytes, just return zero. 
       else if (compBuffer.SequenceEqual(buffer)) { return new byte[] { 0}; } 
      } 

      // Increments 
      index += 1; 
      upperBound += 1; 
     } 

    } 

    throw new TimeoutException("Timeout: Expected buffer was not received prior to timeout"); 
} 
+0

@Sir Rufo 想法先生?非常感謝。 –

+0

此方法只等待一個字節,而不是整個序列。恕我直言,不回答你的問題。如果你想要一個代碼審查,你應該問http://codereview.stackexchange.com/ –

+0

道歉,錯過了我的while循環。啊,不知道codereview,謝謝你的提示。祝你有個好的一天。 –

0

SerialPort.Read()已經阻塞,直到至少有一個字節到達。因此,您不需要(也不應該)以您的方式使用BytesToRead - 您已經引入了一個可疑的忙等待循環。

相反,做這樣的事情:

// Reads 'count' bytes from a serial port into the specified 
// part of a buffer. This blocks until all the bytes have been read. 

public void BlockingRead(SerialPort port, byte[] buffer, int offset, int count) 
{ 
    while (count > 0) 
    { 
     // SerialPort.Read() blocks until at least one byte has been read, or SerialPort.ReadTimeout milliseconds 
     // have elapsed. If a timeout occurs a TimeoutException will be thrown. 
     // Because SerialPort.Read() blocks until some data is available this is not a busy loop, 
     // and we do NOT need to issue any calls to Thread.Sleep(). 

     int bytesRead = port.Read(buffer, offset, count); 
     offset += bytesRead; 
     count -= bytesRead; 
    } 
} 

這裏是你將如何實現的BlockingRead()條款提出你的原始代碼:

public void WaitFor(SerialPort port, byte[] buffer) 
{ 
    byte[] comparisonBuffer = new byte[buffer.Length]; 

    while (true) 
    { 
     BlockingRead(port, comparisonBuffer, 0, comparisonBuffer.Length); 

     if (comparisonBuffer.SequenceEqual(buffer)) 
      return; 
    } 
} 
+0

好的,謝謝。重點不斷重新評估'BytesToRead',但你在這裏寫的東西不提供我要求的功能。 假設你在端口上輸入了10個字節的可用函數,因此count = 10。在計數結束時,計數將被count = = bytesRead帶到0,並釋放循環。 現在我不再等待,無論我收到了什麼。你的函數不會比'port.Read()'做得更多。 –

+0

@GeorgeKerwood是的,它會讀取您要求它讀取的字節數,即傳入的「count」參數。 'SerialPort.Read()'只讀取被調用時的可用字節數。但重新讀你的問題,似乎你要求的東西是不同的...... –

+0

它看起來像你正在嘗試讀取'count'字節的塊,直到一個塊匹配目標數組的內容 - 是正確?你會扔掉任何無與倫比的塊。 –

0

問題

讓我們假設你等待字節模式{1,1,1,2,2}和串口已緩衝{1,1,1,1,2,2,5}

您的代碼讀取前5個字節{1,1,1,1,2},它們將與模式不匹配。但是從端口讀取數據後,您讀取的數據已從緩衝區中刪除,僅包含{2,5},您將永遠無法獲得匹配結果。

解決方案

public void WaitFor(byte[ ] buffer) 
{ 
    if (buffer.Length == 0) 
     return; 

    var q = new List<byte>(buffer.Length); 

    while (true) 
    { 
     var current = _reader.ReadByte(); 
     q.Add((byte)current); 
     // sequence match so far 
     if (q.Last == buffer[ q.Count - 1 ]) 
     { 
      // check for total match 
      if (q.Count == buffer.Length) 
       return; 
     } 
     else 
     { 
      // shift the data 
      while (q.Any() && !q.SequenceEqual(buffer.Take(q.Count))) 
      { 
       q.RemoveAt(0); 
      } 
     } 
    } 
} 
+0

這就是門票!謝謝。 我開始這樣想(讀上一個答案的最後一條評論)。 非常感謝。 –

+0

@GeorgeKerwood但是你可能跳過的所有字節呢?你現在不是把他們扔了嗎?如果他們不重要,他們爲什麼被傳播? –

+0

@MthetheWWatson這應該是一個不同的問題的一部分:o) –

相關問題