C# SerialPort 的“已关闭SafeHandle”
最近在做一个项目,其中有一个部分就是通过USB口转串口,和别人的设备通讯。所以,就要做一个可以自动搜索设备的功能。基本的想法是我先获取所有的端口名,然后再去验证这些端口是不是有设备的那个端口。验证的方法就是先给端口写一些数据,然后再去读这个口,看数据是否有我想要的标志,有的话就是有设备的口。
然后我写了一段程序,感觉没问题,但是运行的时候就会提示“已关闭SafeHandle”,我把代码贴出来(第一段)。我们可以看到我写的一个局部变量 p(SerialPort),每次读写数据完我都会关闭它。网上查了很多资料,说“已关闭SafeHandle”这个错误是因为我的串口还在读写数据,但是资源被释放,所以报错。我反复想来想去,接近崩溃。
后来师兄建议我用SerialPort组件去试试,所以我试了,见第二段代码。当循环运行到“myPort.PortName = portname;”这句时它居然提示我“端口打开时不能更改PortName”,我就觉得很郁闷,因为这个组件我读写完就关闭了。然后我就在更改PortName前加了一个强制关闭串口的代码,它居然就可以了!所以,我想之前那段程序的问题应该是:我表面上虽然已经关闭了局部创建的串口p,但实际上没有关闭,close()方法可能存在某些问题。
所以,我把第一段的程序中的P改为全局变量,不然判断isOpen的时候没有实例,然后加了几句判断是否关闭的代码,结果果然问题解决!见第三段代码。
第一段代码
public class ExpandIO
{
public List<IODevice> Devices = new List<IODevice>();
public void Detect()
{
try
{
SerialPort.GetPortNames();
foreach (string portname in SerialPort.GetPortNames())
{
if (!Devices.Exists(x => x.PortName == portname))
{
try
{
char[] b = { ':', 'D', 'T', 'C', 'T' };
SerialPort p = new SerialPort(portname, 115200, Parity.None, 8, StopBits.One);
p.ReadTimeout = 1000;
p.WriteTimeout = 1000;
if (!p.IsOpen)
{
p.Open();
Thread.Sleep(100);
p.Write(b, 0, 5);
Thread.Sleep(100);
p.Read(b, 0, 5);
p.Close();
Thread.Sleep(100);
if (b[0] == 'O' && b[1] == 'K')
{
IODevice d = new IODevice
{
PortName = portname,
id = (byte)b[2]
};
Devices.Add(d);
}
}
}
catch { }
}
}
}
catch { }
foreach (IODevice dev in Devices)
{
dev.start();
}
第二段代码
// TODO: 查找输出设备
void Detect()
{
try
{
foreach (string portname in SerialPort.GetPortNames())
{
if (!myDevices.Exists(x => x.PortName == portname))
{
try
{
char[] b = { ':', 'D', 'T', 'C', 'T' };
// 注释的这部分是后来加的
//while (myPort.IsOpen)
//{
// myPort.Close();
//}
myPort.PortName = portname;
if (!myPort.IsOpen)
{
myPort.Open();
myPort.DiscardInBuffer();
myPort.DiscardOutBuffer();
Thread.Sleep(100);
myPort.Write(b, 0, 5);
Thread.Sleep(100);
myPort.Read(b, 0, 5);
myPort.Close();
Thread.Sleep(100);
if (b[0] == 'O' && b[1] == 'K')
{
IODevice d = new IODevice
{
PortName = portname,
id = (byte)b[2]
};
myDevices.Add(d);
}
}
}
catch { }
}
}
}
catch { }
}
第三段代码
public class ExpandIO
{
public List<IODevice> Devices = new List<IODevice>();
SerialPort p = new SerialPort("COM1", 115200, Parity.None, 8, StopBits.One);
public void Detect()
{
try
{
foreach (string portname in SerialPort.GetPortNames())
{
if (!Devices.Exists(x => x.PortName == portname))
{
try
{
char[] b = { ':', 'D', 'T', 'C', 'T' };
while (p.IsOpen)
{
p.Close();
}
p = new SerialPort(portname, 115200, Parity.None, 8, StopBits.One);
p.ReadTimeout = 1000;
p.WriteTimeout = 1000;
if (!p.IsOpen)
{
p.Open();
Thread.Sleep(100);
p.Write(b, 0, 5);
Thread.Sleep(100);
p.Read(b, 0, 5);
p.Close();
Thread.Sleep(100);
if (b[0] == 'O' && b[1] == 'K')
{
IODevice d = new IODevice
{
PortName = portname,
id = (byte)b[2]
};
Devices.Add(d);
}
}
}
catch { }
}
}
foreach (IODevice dev in Devices)
{
dev.start();
}
}
catch { }
}