SerialPort.Read(....) 不尊重 ReadTimeOut [英] SerialPort.Read(....) does not respect ReadTimeOut

查看:47
本文介绍了SerialPort.Read(....) 不尊重 ReadTimeOut的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Got a bug in some legacy code which communicates with a payment terminal.

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

Just before a new payment is started, the code attempts to clear the internal read buffer of the SerialPort.

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

I trimmed the code down to the bare minimum. It uses the .NET SerialPort type. A read timeout of 50ms is set. Then it reads 512 bytes and continues doing so until no more bytes are read or until a TimeoutException is thrown.

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

We added a bunch of logging and it showed that the call to the first Read(...) method sometimes takes 10 - 15 minutes, even with a timeout of 50ms. Then a TimeoutException is thrown and the application continues. But during the Read(...) the application hangs.

这并不总是发生,Windows 2000 机器由于某种原因似乎更容易出现此错误.

This doesn't always happen, Windows 2000 machines seem more prone to this error for some reason.

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 端口.

PS: Most error reports are coming from W2K machines where the device is connected to an EdgePort, which simulates a bunch of virtual COM ports. Its driver creates a bunch (8 or so) local COM port.

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

But we also have reports from Windows 7. We can also reproduce the issue if we directly connect the device to the PC (no EdgePort). However not as often and when it happens the delay it not 10 minutes, but more like 1 - 2 minutes.

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

Update: Tried a lot of things to fix this. Was hard to reproduce, but occurred quite often in the field because there it is distributed on thousand of PCs. Actually replaced the .NET 2.0 SerialPort type with another open source version. Worked without a problem on the one PC where we could actually reproduce it like 60 - 70% of the time. But alas, during a pilot test in production the problems still continued to occur.

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

The code for the payment terminal was written a couple of years earlier and I ported it to anonther application. During the port I re-factored some code, but kept the original functionality. When communicating with the terminal the code would:

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

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

Meanwhile the main thread had a while loop which contained a Thread.Sleep(50) and an Application.DoEvents() call (yuck!). I refactored this whole "wait loop" out of it and made use of a WaitHandle (AutoResetEvent / ManualResetEvent). I just waited until this handle was set. Worked without a problem, but on certain PCs all serial port communication would freeze for minutes until something triggered it. Re-enabled the Application.DoEvents() way of working and the problems were gone.

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

It is still in there unfortunately, a riddle to me why it is required here and why it causes such severe side effects. The applications supports 5 other types of serial port devices. Communicating with these devices never required anything like this.

推荐答案

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

maybe adding a test on port's 'bytes to read' may help steer clear of badly coded drivers:

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

更好的是,使用

_serialPort.DiscardInBuffer();

相反!

这篇关于SerialPort.Read(....) 不尊重 ReadTimeOut的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆