如何使用.NET/C#进行强大的SerialPort编程?我正在编写一个Windows服务来与串行磁条阅读器和中继板(访问控制系统)进行通信。在另一个程序通过打开与我的服务相同的串行端口“中断”进程后,我遇到了代码停止工作的问题(我得到了IOExceptions)。部分代码如下:publicpartialclassService:ServiceBase{ThreadthreadDoorOpener;publicService(){threadDoorOpener=newThread(DoorOpener);}publicvoidDoorOpener(){while(true){SerialPortserialPort=newSerialPort();线程.睡眠(1000);字符串[]端口=SerialPort.GetPortNames();serialPort.PortName="COM1";串行端口.BaudRate=9600;串行端口.DataBits=8;serialPort.StopBits=StopBits.One;serialPort.Parity=Parity.None;如果(serialPort.IsOpen)serialPort.Close();串行端口.Open();serialPort.DtrEnable=true;线程.睡眠(1000);串行端口.关闭();}}publicvoidDoStart(){threadDoorOpener.Start();}publicvoidDoStop(){threadDoorOpener.Abort();}protectedoverridevoidOnStart(string[]args){DoStart();}protectedoverridevoidOnStop(){DoStop();}}我的示例程序成功启动工作线程,DTR打开/关闭并提升我的磁条阅读器的电源(等待1秒),关闭(等待1秒)等等。如果我启动HyperTerminal并连接到同一个COM端口,HyperTerminal会告诉我该端口当前正在使用中。如果我在HyperTerminal中反复按ENTER,试图重新打开端口,重试几次后它会成功。这会在我的工作线程中导致IOExceptions,这是预期的。但是,即使我关闭超级终端,我的工作线程中仍然会出现相同的IOException。唯一的方法是重新启动计算机。其他程序(不使用.NET库进行端口访问)此时似乎工作正常。关于可能导致此问题的任何想法?@thomask是的,超级终端确实在SetCommState的DCB中启用了fAbortOnError,这解释了SerialPort对象抛出的大多数IOExceptions。一些PC/手持设备也有默认打开错误标志中止的UART——因此串行端口的初始化例程必须清除它(微软忽略这一点)。我最近写了一篇很长的文章来更详细地解释这一点(如果您有兴趣,请参阅此)。您不能关闭其他人与端口的连接,以下代码将永远无法工作:if(serialPort.IsOpen)serialPort.Close();由于您的对象没有打开端口,因此您无法关闭它。即使发生异常,也应该关闭并处理串口}serialPort.Dispose();如果你希望进程是可中断的,那么你应该检查端口是否打开,然后退出一段时间再试一次,例如。而(serialPort.IsOpen){Thread.Sleep(200);您是否尝试过在应用程序中打开端口,打开/关闭DtrEnable,然后在应用程序关闭时关闭端口?即:使用(SerialPortserialPort=newSerialPort("COM1",9600)){serialPort.Open();while(true){Thread.Sleep(1000);serialPort.DtrEnable=true;线程.睡眠(1000);串行端口.DtrEnable=false;}serialPort.Close();我不熟悉DTR语义,所以我不知道这是否可行。如何进行可靠的异步通信不要使用阻塞方法,内部帮助类有一些细微的错误。将APM与会话状态类一起使用,其实例管理缓冲区和跨调用共享的缓冲区游标,以及将EndRead包装在try...catch中的回调实现。在正常操作中,try块应该做的最后一件事是通过调用BeginRead()设置下一个重叠I/O回调。当出现问题时,catch应该异步调用restart方法的委托。回调实现应在catch块之后立即退出,以便重启逻辑可以销毁当前会话(会话状态几乎肯定已损坏)并创建一个新会话。不能在会话状态类上实现重启方法,因为这会阻止它销毁和重新创建会话。当SerialPort对象关闭时,可能会有挂起的I/O操作(这将在应用程序退出时发生)。如果是这样,关闭SerialPort将触发回调,并且在这些条件下,EndRead将抛出一个与通用通信shitfit无法区分的异常。您应该在会话状态中设置一个标志以抑制catch块中的重新启动行为。这将防止重启方法干扰自然关机。可以依赖此体系结构而不是意外地持久化SerialPort对象。restart方法管理串行端口对象的关闭和重新打开。在SerialPort对象上调用Close()之后,调用Thread.Sleep(5)给它一个释放的机会。其他东西可以抢占端口,所以当你重新打开它时要准备好处理它。我想我得出的结论是超级终端运行不佳。我运行了以下测试:在“控制台模式”下启动我的服务,它开始打开/关闭设备(我可以通过它的LED判断)。启动超级终端并连接到该端口。设备保持打开状态(超级终端提高DTR)我的服务写入事件日志并且无法打开端口停止超级终端,我使用任务管理器验证它已正确关闭设备保持关闭状态(超级终端降低DTR)并且我的应用程序继续写入到事件日志说它无法打开端口。我启动第三个应用程序(我需要共存的应用程序)并告诉它连接到端口。我做到了。这里没有错误。停止上述申请。瞧,我的服务又启动了,端口成功打开,LED灯亮起/熄灭。我试过像这样更改工作线程,结果完全相同。一旦超级终端成功“捕获端口”(当我的线程处于休眠状态时),我的服务将无法再次打开该端口。publicvoidDoorOpener(){while(true){SerialPortserialPort=newSerialPort();线程.睡眠(1000);serialPort.PortName="COM1";串行端口.BaudRate=9600;串行端口.DataBits=8;serialPort.StopBits=StopBits.One;serialPort.Parity=Parity.None;尝试{serialPort.Open();}catch{}if(serialPort.IsOpen){serialPort.DtrEnable=true;线程.睡眠(1000);串行端口.关闭();}serialPort.Dispose();这段代码似乎工作正常。我已经在我本地机器上的控制台应用程序中测试了它,使用ProcommPlus打开/关闭端口,程序一直在滴答作响。使用(SerialPortport=newSerialPort("COM1",9600)){while(true){Thread.睡眠(1000);试试{控制台。Write("打开...");港口。打开();港口。DtrEnable=真;线程.睡眠(1000);端口.关闭();Console.WriteLine("关闭");}catch{Console.WriteLine("打开串口出错");}finally{if(port.IsOpen)port.Close();这个答案有很长的评论......我相信当你的程序处于Thread.Sleep(1000)并打开超级终端连接时,超级终端会控制串行端口。当您的程序唤醒并尝试打开串行端口时,将抛出IOException。重新设计您的方法并尝试以不同的方式处理端口的打开。编辑:关于程序失败时必须重新启动计算机的问题...可能是您的程序实际上并未关闭,请打开任务管理器并查看是否可以找到您的程序服务。请务必在退出应用程序之前停止所有线程。您的服务“拥有”该端口是否有充分的理由?看看内置的UPS服务——一旦你告诉它有一个UPS连接到COM1,你就可以和那个端口说再见了。我建议你这样做,除非有强烈的操作需求来共享端口。以上就是C#学习教程:如何使用.NET/C#进行强大的SerialPort编程?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
