.net 检测 SerialPort 何时断开连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13408476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detecting when a SerialPort gets disconnected
提问by
I have an open SerialPortand receive data through the DataReceivedevent.
我SerialPort通过DataReceived事件打开并接收数据。
Is there any way to detect if the SerialPortgets disconnected?
有没有办法检测是否SerialPort断开连接?
I tried the ErrorReceivedand PinChangedevents but no luck.
我尝试了ErrorReceived和PinChanged事件,但没有运气。
In addition to that, SerialPort.IsOpenreturns true when physically disconnected.
除此之外,SerialPort.IsOpen在物理断开连接时返回 true。
采纳答案by Matt Burland
USB-serial ports are a hugepain. See, for example, this question. I'm not sure whether it really was fixed with .NET 4.0, but back in the day I tried to deal with the problem of disconnections crashing the whole program with something like this:
USB 串行端口是一个巨大的痛苦。例如,请参阅此问题。我不确定它是否真的是用 .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);
}
}
Apologies to whoever I adapted this from, it seems I failed to make a note of it in my code. The problem apparently stemmed from how .NET handled the underlying stream in the case of the serial port disappearing. It seemed you couldn't close the stream after the serial port is disconnected.
向我从谁那里改编的道歉,似乎我没有在我的代码中记下它。问题显然源于.NET 如何在串行端口消失的情况下处理底层流。串口断开后,您似乎无法关闭流。
Another strategy I used was to create a small program that did just the serial communication part and exposed a WCF service for my main program to connect to. That way, when the USB-serial adapter flakes out and crashes the communication program, I can just automatically restart it from my main program.
我使用的另一个策略是创建一个小程序,它只执行串行通信部分并公开一个 WCF 服务供我的主程序连接。这样,当 USB 串行适配器脱落并使通信程序崩溃时,我可以从主程序中自动重新启动它。
Finally, I don't know why nobody ever marketed a locking USB port to avoid the whole accidental disconnection problem, especially with USB-serial adapters!
最后,我不知道为什么没有人销售锁定 USB 端口来避免整个意外断开连接的问题,尤其是使用 USB 串行适配器时!
回答by kyndigs
The problem is that IsOpenvalue is only set back to falsewhen the Closemethod is executed.
问题是IsOpen仅false在Close执行方法时才将值设置回。
You could try caputuring the WM_DEVICECHANGEmessage and using that.
您可以尝试捕获WM_DEVICECHANGE消息并使用它。
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx
回答by Rev1.0
I also faced the problem of an unhandleable exception (and not being able to detect/circumvent the problem in code) as soon as the USB-Serial adapter had been disconnected. I can confirm that the solution from Mattt Burland works.
一旦 USB 串行适配器断开连接,我还面临无法处理的异常问题(并且无法检测/规避代码中的问题)。我可以确认 Mattt Burland 的解决方案有效。
Simplified version:
简化版:
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);
}
}
}
回答by Jon B
If the device you're connecting to uses the CD pin, you can watch for that to change (other pins may apply for some devices using flow control). If not, then there isn't really a definitive way to do this.
如果您要连接的设备使用 CD 引脚,您可以观察它的变化(其他引脚可能适用于使用流量控制的某些设备)。如果没有,那么就没有真正确定的方法来做到这一点。
Depending on the expected behavior of the connected device, you might want to implement a timeout or some kind of keep alive.
根据连接设备的预期行为,您可能想要实现超时或某种保持活动状态。
回答by Seelixh
I solved this problem with a simple backgroundworker. I continuously check/set all current ports into an array and if new ports are different to my ports-array I get the changed ports from these 2 arrays.
我用一个简单的后台工作者解决了这个问题。我不断地检查/设置所有当前端口到一个数组中,如果新端口与我的端口数组不同,我会从这 2 个数组中获取更改的端口。
Example:
例子:
// 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);
}
}
回答by dcarl661
Use the C# SerialPort.CDHolding flag.
使用 C# SerialPort.CDHolding 标志。
So save the bool to a lastCDHolding flag, before your open and read loop.
因此,在打开和读取循环之前,将 bool 保存到 lastCDHolding 标志。
After you read test SerialPort.CDHolding != lastCDHolding to trap changes or just test SerialPort.CDHoldin==false to detect the port was closed.
在您阅读 test SerialPort.CDHolding != lastCDHolding 以捕获更改或仅测试 SerialPort.CDHoldin==false 以检测端口已关闭后。

