SerialPort.Read(....)不尊重ReadTimeOut

Chr*_*ers 3 c# serial-port

在与支付终端通信的一些遗留代码中出现了错误.

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

我将代码调整到最低限度.它使用.NET SerialPort类型.设置读取超时50ms.然后它读取512个字节并继续这样做,直到不再读取字节或抛出TimeoutException为止.

我们添加了一堆日志记录,它显示对第一个Read(...)方法的调用有时需要10到15分钟,即使超时为50ms.然后抛出TimeoutException并继续应用程序.但在Read(...)期间应用程序挂起.

这并不总是发生,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) {}
    }
}
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏.

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

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

更新:尝试了很多东西来解决这个问题.难以重现,但在现场经常发生,因为它分布在数千台PC上.实际上用另一个开源版本替换了.NET 2.0 SerialPort类型.在一台PC上没有问题的地方工作,我们实际上可以像60-70%的时间那样重现它.但是,在生产中的试点测试中,问题仍然存在.

付款终端的代码是在几年前编写的,我把它移植到另一个应用程序中.在端口期间,我重新考虑了一些代码,但保留了原始功能.与终端通信时,代码将:

  1. 从线程池中触发另一个线程
  2. 将消息发送到设备
  3. 从串行端口读取,直到收到响应或发生超时.

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

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

zeF*_*chy 7

可能在端口的"要读取的字节"上添加测试可能有助于避免编码错误的驱动程序:

length = (_serialPort.BytesToRead > 0) ? _serialPort.Read(buffer, 0, 512) : 0;
Run Code Online (Sandbox Code Playgroud)

更好的是,使用

_serialPort.DiscardInBuffer();
Run Code Online (Sandbox Code Playgroud)

代替!