有一个遗留代码中存在的bug,该代码与支付终端通信。
在开始新的支付之前,代码尝试清除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) {}
}
}
非常感谢您的帮助。
PS:大多数错误报告来自连接到EdgePort的W2K机器,该设备模拟了一堆虚拟COM端口。其驱动程序创建了一堆(大约8个)本地COM端口。
但是我们也有来自Windows 7的报告。如果我们直接将设备连接到PC(没有EdgePort),我们也可以复制此问题。但不如经常发生,而且当发生延迟时不是10分钟,而是1-2分钟。
更新:尝试了很多方法来修复此问题。很难复制,但在现场由于分布在成千上万的PC上,它经常发生。实际上,用另一个开源版本替换了.NET 2.0 SerialPort类型。在我们能够实际复制它的一个PC上,工作得毫无问题,但遗憾的是,在生产中进行试点测试时,问题仍然继续发生。
支付终端的代码是几年前编写的,我将其移植到了另一个应用程序中。在移植过程中,我重构了一些代码,但保留了原始功能。与终端通信时,代码将:
- 从线程池中启动另一个线程
- 将消息发送到设备
- 从串行端口读取,直到收到响应或超时为止。
同时,主线程具有一个while循环,其中包含Thread.Sleep(50)和Application.DoEvents()调用(yuck!)。我重构了整个“等待循环”,并使用了WaitHandle(AutoResetEvent / ManualResetEvent)。我只是等到此句柄被设置。工作得毫无问题,但在某些PC上,所有串行端口通信都会冻结几分钟,直到触发某些内容。重新启用Application.DoEvents()工作方式,问题就解决了。
不幸的是,它仍然存在,对我来说是一个谜,为什么在这里需要它以及为什么会导致如此严重的副作用。该应用程序支持其他5种类型的串行端口设备。与这些设备通信从未需要过类似的内容。