检测SerialPort何时断开连接

时间:2012-11-16 00:12:07

标签: .net winforms

我有一个开放的SerialPort并通过DataReceived事件接收数据。

有没有办法检测SerialPort是否已断开连接?

我尝试了ErrorReceivedPinChanged事件,但没有运气。

除此之外,SerialPort.IsOpen在物理断开连接时返回true。

7 个答案:

答案 0 :(得分:12)

USB串口是一种巨大的痛苦。例如,请参阅this question。我不确定它是否真的是用.NET 4.0修复的,但是当天我试图用这样的事情来解决整个程序崩溃的问题:

public class SafeSerialPort : SerialPort
{
    private Stream theBaseStream;

    public SafeSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        : base(portName, baudRate, parity, dataBits, stopBits)
    {

    }

    public new void Open()
    {
        try
        {
            base.Open();
            theBaseStream = BaseStream;
            GC.SuppressFinalize(BaseStream);
        }
        catch
        {

        }
    }

    public new void Dispose()
    {
        Dispose(true);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && (base.Container != null))
        {
            base.Container.Dispose();               
        }
        try
        {
            if (theBaseStream.CanRead)
            {
                theBaseStream.Close();
                GC.ReRegisterForFinalize(theBaseStream);
            }
        }
        catch
        {
            // ignore exception - bug with USB - serial adapters.
        }
        base.Dispose(disposing);
    }
}

向我改编的人致歉,似乎我没有在我的代码中记下它。问题显然源于.NET在串口消失的情况下如何处理底层流。在断开串口后,似乎无法关闭流。

我使用的另一个策略是创建一个只执行串行通信部分的小程序,并为我的主程序提供WCF服务以进行连接。这样,当USB串行适配器脱落并崩溃通信程序时,我可以自动从主程序重新启动它。

最后,我不知道为什么没有人销售锁定USB端口以避免整个意外断线问题,尤其是USB串口适配器!

答案 1 :(得分:2)

问题是IsOpen值仅在执行false方法时设置回Close

您可以尝试捕获WM_DEVICECHANGE消息并使用该消息。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx

答案 2 :(得分:2)

一旦USB-Serial适配器断开连接,我也遇到了一个不可处理的异常问题(并且无法检测/规避代码中的问题)。我可以确认Mattt Burland的解决方案是有效的。

简化版:

class SafeSerialPort : SerialPort {
    public new void Open() {
        if (!base.IsOpen) {
            base.Open();
            GC.SuppressFinalize(this.BaseStream);
        }
    }

    public new void Close() {
        if (base.IsOpen) {
            GC.ReRegisterForFinalize(this.BaseStream);
            base.Close();   
        }           
    }

    protected override void Dispose(bool disposing) {
        try {
            base.Dispose(disposing);
        } catch (Exception ex) {
            Debug.WriteLine(ex.Message);
        }

    }
}

答案 3 :(得分:1)

如果您要连接的设备使用CD引脚,您可以注意要更改(其他引脚可能适用于使用流量控制的某些设备)。如果没有,那么就没有确切的方法来做到这一点。

根据所连接设备的预期行为,您可能希望实现超时或某种保持活动状态。

答案 4 :(得分:0)

我用一个简单的背景工作者解决了这个问题。 我不断检查/设置所有当前端口到一个阵列,如果新端口与我的ports-array不同,我从这两个阵列获得更改的端口。

示例:

// global variable
List<string> oldPorts = new List<string>();    // contains all connected serial ports

private void bgw_checkSerialPorts_DoWork(object seder, DoWorkEventArgs e)
{
    while (true)
    {
        string[] currentPorts = SerialPort.GetPortNames();    // get all connected serial ports
        string[] diffPorts = currentPorts.Except(oldPorts.ToArray());    // get the differences between currentPorts[] and oldPorts-list

        if (diffPorts.Length > 0)
        {
            // iterate all changed ports
            for (int i = 0; i < diff.Length; i++)
            {
                // check if changed port was in old list
                if (oldPorts.Contains(diff[i]))
                {
                    // port in diff[] was removed
                }
                else
                {
                    // port in diff[] is a new device
                }
            }
        }

        oldPorts = currentPorts.ToList();   // update oldPortlist

        // check every 100ms
        Thread.Sleep(100);
    }
}

答案 5 :(得分:0)

使用C#SerialPort.CDHolding标志。

因此,在打开和读取循环之前,将bool保存到lastCDHolding标志。

在您阅读测试SerialPort.CDHolding!= lastCDHolding以捕获更改或仅测试SerialPort.CDHoldin == false以检测端口已关闭。

答案 6 :(得分:0)

针对仍面临此问题的人员进行更新;几点...

  1. 告诉用户“不要断开USB设备的连接”是徒劳的,只会惹恼所有相关人员。即使我们希望他们不会,我们知道他们会在我们的程序运行时将设备拉出...
  2. 早期版本的框架 did 会在yank上立即更新SerialPort.GetPortNames(),但是4.7不会更新开放端口的列表。我们有一个后台线程检查此列表是否有更改(如上所述),该更改过去效果很好,但不再起作用...
  3. 由于此框架更改(错误?),我们更新了检查线程以测试SerialPort.IsOpen(),在4.7中,该线程立即报告用户退出设备时设备已关闭。我们确实在yank上立即看到WM_DEVICECHANGE消息,但对于我们的应用程序,只需在后台线程中测试SerialPort.IsOpen()就更容易了。

希望有帮助, 最好的问候,戴夫