我有一个开放的SerialPort
并通过DataReceived
事件接收数据。
有没有办法检测SerialPort
是否已断开连接?
我尝试了ErrorReceived
和PinChanged
事件,但没有运气。
除此之外,SerialPort.IsOpen
在物理断开连接时返回true。
答案 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)
针对仍面临此问题的人员进行更新;几点...
SerialPort.GetPortNames()
,但是4.7不会更新开放端口的列表。我们有一个后台线程检查此列表是否有更改(如上所述),该更改过去效果很好,但不再起作用... SerialPort.IsOpen()
,在4.7中,该线程立即报告用户退出设备时设备已关闭。我们确实在yank上立即看到WM_DEVICECHANGE
消息,但对于我们的应用程序,只需在后台线程中测试SerialPort.IsOpen()
就更容易了。希望有帮助, 最好的问候,戴夫