2016-09-05 32 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) –

相关问题