在与支付终端通信的某些遗留代码中发现了一个错误。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%的时间内实际再现它。但是,唉,在生产试验中,问题仍然存在。
支付终端的代码是在几年前编写的,我将它移植到其他应用程序中。在端口期间,我重新考虑了一些代码,但保留了原始功能。当与终端进行通信的代码将:
- 断火从线程池
- 另一个线程将消息发送到从串口阅读设备
- 直到响应已接收到或发生超时。
与此同时,主线程有一个while循环,其中包含一个Thread.Sleep(50)和一个Application.DoEvents()调用(yuck!)。我重构了整个“等待循环”,并使用WaitHandle(AutoResetEvent/ManualResetEvent)。我只是等待,直到这个句柄被设置。在没有问题的情况下工作,但在某些PC上,所有串行端口通信都会冻结数分钟,直到触发它为止。重新启用Application.DoEvents()的工作方式,问题消失了。
它仍然在那里,不幸的是,这是一个谜,为什么这里需要它,以及为什么它会导致如此严重的副作用。该应用程序支持5种其他类型的串行端口设备。与这些设备通信从来不需要这样的东西。
不确定您是否看到这篇文章:http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/dc8f858c-8f6f-4184-aac6-02ac88dc5e77。任何机会,硬件/供应商特定? – reuben
我原以为这是与驱动程序相关的东西。行为是否与操作系统有关?还是只是说你的win2000机器可能有一个狡猾的UART +驱动程序? – zeFrenchy
不,也从Windows 7机器报告。所以可能不会绑定到操作系统本身。但所有使用相同的EdgePort硬件/驱动程序。 –