2012-07-05 90 views
3

在与支付终端通信的某些遗留代码中发现了一个错误。SerialPort.Read(....)不尊重ReadTimeOut

就在开始新付款之前,代码会尝试清除SerialPort的内部读取缓冲区。

我将代码修剪到最低限度。它使用.NET SerialPort类型。读取超时时间为50ms。然后它读取512个字节并继续这样做直到不再读取字节或者引发TimeoutException。

我们添加了一堆日志记录,它显示了对第一个Read(...)方法的调用有时需要10 - 15分钟,即使是50ms的超时也是如此。然后引发TimeoutException并继续应用程序。但在阅读(...)应用程序挂起。

这并不总是会发生,Windows 2000机器出于某种原因似乎更容易出现此错误。

public class Terminal 
{ 
    private SerialPort _serialPort = new SerialPort(); 

    public void ClearReadBuffer() 
    { 
     try 
     { 
      _serialPort.ReadTimeout = 50; 
      int length; 
      do 
      { 
       var buffer = new byte[512]; 
       length = _serialPort.Read(buffer, 0, 512); 
      } while (length > 0); 
     } 
     catch (TimeoutException) {} 
    } 
} 

任何帮助表示赞赏。

PS:大多数错误报告都来自W2K机器,其中设备连接到EdgePort,它模拟一组虚拟COM端口。它的驱动程序创建了一堆(大约8个)本地COM端口。

但是我们也有来自Windows 7的报告。如果我们直接将设备连接到PC(无EdgePort),我们也可以重现该问题。然而,并不经常,当它发生延迟不是10分钟,而是更像1 - 2分钟。

更新:尝试了很多事情来解决这个问题。很难复制,但在现场经常发生,因为它分布在数千台个人电脑上。实际上将.NET 2.0 SerialPort类型替换为另一个开源版本。在一台PC上没有任何问题地工作,我们可以在60-70%的时间内实际再现它。但是,唉,在生产试验中,问题仍然存在。

支付终端的代码是在几年前编写的,我将它移植到其他应用程序中。在端口期间,我重新考虑了一些代码,但保留了原始功能。当与终端进行通信的代码将:

  1. 断火从线程池
  2. 另一个线程将消息发送到从串口阅读设备
  3. 直到响应已接收到或发生超时。

与此同时,主线程有一个while循环,其中包含一个Thread.Sleep(50)和一个Application.DoEvents()调用(yuck!)。我重构了整个“等待循环”,并使用WaitHandle(AutoResetEvent/ManualResetEvent)。我只是等待,直到这个句柄被设置。在没有问题的情况下工作,但在某些PC上,所有串行端口通信都会冻结数分钟,直到触发它为止。重新启用Application.DoEvents()的工作方式,问题消失了。

它仍然在那里,不幸的是,这是一个谜,为什么这里需要它,以及为什么它会导致如此严重的副作用。该应用程序支持5种其他类型的串行端口设备。与这些设备通信从来不需要这样的东西。

+0

不确定您是否看到这篇文章:http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/dc8f858c-8f6f-4184-aac6-02ac88dc5e77。任何机会,硬件/供应商特定? – reuben

+0

我原以为这是与驱动程序相关的东西。行为是否与操作系统有关?还是只是说你的win2000机器可能有一个狡猾的UART +驱动程序? – zeFrenchy

+0

不,也从Windows 7机器报告。所以可能不会绑定到操作系统本身。但所有使用相同的EdgePort硬件/驱动程序。 –

回答

7

可能增加端口的测试“读取字节”,可能有助于避开编码错误的驱动程序:

length = (_serialPort.BytesToRead > 0) ? _serialPort.Read(buffer, 0, 512) : 0; 

更好的是,使用

_serialPort.DiscardInBuffer(); 

,而不是!

+0

我期望DiscardInBuffer能够解决这个问题,很好地发现它是否可行。 – Peter

+0

重写了ClearBuffer方法。首先清除Windows驱动程序缓冲区(DiscardInBuffer),然后是SerialPort的内部缓冲区(如果存在任何内容)。这不再被阻塞,因为大部分时间Read(...)方法都没有被调用。然而,SerialPort实例在后续Write(...)上仍然冻结5-10分钟。奇怪的东西,实际上取代了.NET(2.0)SerialPort类型。现在工作正常。 –

+0

@Christophe Geers我一直在处理一个听起来很像这样的问题。你的意思是你最终用你自己的实现重写了.NET串口类型吗?您是否有更多的见解来分享究竟是什么问题或哪些部分必须改变? – mickeyf