3

在一些与支付终端通信的遗留代码中存在错误。

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

我将代码缩减到最低限度。它使用 .NET SerialPort 类型。设置了 50 毫秒的读取超时。然后它读取 512 个字节并继续这样做,直到不再读取字节或抛出 TimeoutException。

我们添加了一堆日志记录,它表明调用第一个 Read(...) 方法有时需要 10 到 15 分钟,即使超时时间为 50 毫秒。然后抛出 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) {}
    }
}

任何帮助表示赞赏。

PS:大多数错误报告来自设备连接到 EdgePort 的 W2K 机器,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() 调用(糟糕!)。我重构了整个“等待循环”,并使用了 WaitHandle (AutoResetEvent / ManualResetEvent)。我只是等到这个句柄被设置。工作没有问题,但在某些 PC 上,所有串行端口通信都会冻结几分钟,直到有东西触发它。重新启用 Application.DoEvents() 的工作方式,问题就消失了。

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

4

1 回答 1

7

也许在端口的“要读取的字节”上添加一个测试可能有助于避开编码错误的驱动程序:

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

更好的是,使用

_serialPort.DiscardInBuffer();

反而!

于 2012-07-05T08:38:41.073 回答