在某些与付款终端进行通讯的旧版代码中发现了一个错误。
在开始新的付款之前,代码将尝试清除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上工作没问题,我们实际上可以60-70%的时间重现它。但是可惜的是,在生产中的试点测试期间,问题仍然继续发生。
付款终端的代码是几年前编写的,我将其移植到其他应用程序中。在移植期间,我重构了一些代码,但保留了原始功能。与终端通信时,代码将:
从线程池中触发另一个线程
发送消息到设备
从串行端口读取,直到收到响应或发生超时。
同时,主线程有一个while循环,其中包含Thread.Sleep(50)和Application.DoEvents()调用(糟糕!)。我从中重构了整个“等待循环”,并使用了WaitHandle(AutoResetEvent / ManualResetEvent)。我只是等到设置此句柄。可以正常工作,但是在某些PC上,所有串行端口通信都会冻结几分钟,直到有东西触发它为止。重新启用Application.DoEvents()的工作方式,问题消失了。
不幸的是,它仍然在那里,给我一个谜,为什么在这里需要它以及为什么会引起如此严重的副作用。该应用程序支持其他5种类型的串行端口设备。与这些设备进行通信从来不需要这样的事情。
最佳答案
也许在端口的“要读取的字节”上添加测试可能有助于避免不良编码的驱动程序:
length = (_serialPort.BytesToRead > 0) ? _serialPort.Read(buffer, 0, 512) : 0;
更好,使用
_serialPort.DiscardInBuffer();
代替!
关于c# - SerialPort.Read(…)不尊重ReadTimeOut,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11340513/