Linux树莓派下.NET5控制台程序开机自启自动退出如何解决?
报错根因
systemd开机自启的后台服务没有关联交互式控制台,Console.ReadKey() 方法依赖控制台输入流才能运行,无控制台环境下就会抛出你遇到的异常,你用这个方法的目的是阻塞主进程避免程序退出,只要替换成不依赖控制台的阻塞逻辑即可。
可用解决方案
方案1:极简适配,仅替换阻塞逻辑
直接把代码中的Console.ReadKey();替换为以下代码即可:
// 先引入命名空间 using System.Threading; // 替换原Console.ReadKey()的位置 while (true) { Thread.Sleep(Timeout.Infinite); }
该逻辑不需要依赖任何控制台资源,后台运行时可以持续阻塞主进程,不会影响串口数据接收的事件回调。
方案2:规范服务化改造,支持优雅启停
如果需要适配后台服务的生命周期管理(比如收到停止指令时自动关闭串口、释放资源),可以用.NET通用主机托管程序:
- 先安装NuGet依赖包
Microsoft.Extensions.Hosting - 改写Main方法如下:
using Microsoft.Extensions.Hosting; using System.Text; using System.IO.Ports; using System.Linq; namespace ConsoleApp1 { internal class Program { private static SerialPort SP1 = new SerialPort("/dev/ttyUSB0", 57600, Parity.None, 8, StopBits.One); private static SerialPort SP2 = new SerialPort("/dev/ttyUSB1", 115200, Parity.None, 8, StopBits.One); static void Main(string[] args) { var host = Host.CreateDefaultBuilder(args).Build(); // 原有串口初始化逻辑 SP1.DataReceived += SP_DataReceived; try { SP1.Open(); SP2.Open(); // 注册停止事件,退出时释放串口资源 host.AppLifetime.ApplicationStopping.Register(() => { SP1.Close(); SP1.Dispose(); SP2.Close(); SP2.Dispose(); }); } catch(Exception ex){ Console.WriteLine(ex.Message); return; } Console.WriteLine("Started"); host.Run(); } static List<byte> ByteList = new List<byte>(); // 原有SP_DataReceived方法保持不变 private static void SP_DataReceived(object sender, SerialDataReceivedEventArgs e) { byte[] buf = new byte[SP1.BytesToRead]; Console.WriteLine("DATA RECEIVED!"); SP1.Read(buf, 0, buf.Length); foreach (Byte b in buf) { ByteList.Add(b); } int StartIndex = -1; int EndIndex = -1; for (int i = 0; i < ByteList.Count; i++) { if (ByteList[i] == 2) { StartIndex = i; } else if (ByteList[i] == 13 && ByteList.Count-1 > i && ByteList[i+1]==10) { EndIndex = i + 1; break; } } List<byte> NewByteList = new List<byte>(); if (StartIndex != -1 && EndIndex != -1) { for (int i = StartIndex+1; i <= EndIndex-2; i++) { NewByteList.Add(ByteList[i]); } } ByteList.RemoveRange(StartIndex, EndIndex - StartIndex+1); var Result = Encoding.UTF8.GetString(NewByteList.ToArray()).Split(" ").Last().Replace(Environment.NewLine, ""); if (!string.IsNullOrEmpty(Result)) { Console.WriteLine(Result); if (SP2.IsOpen) { SP2.Write(Result+Environment.NewLine); } else { Console.WriteLine("SP2 is not opened"); } } } } }
附加优化建议
- 你配置的systemd服务单元可以添加
Restart=always配置项,程序异常崩溃时会自动重启,提升服务稳定性 - 不要使用
/dev/ttyUSB0这类可变路径,建议用/dev/serial/by-id/目录下对应串口的固定唯一路径,避免重启或插拔设备后串口序号变化导致功能异常
内容的提问来源于stack exchange,提问作者Melon NG
相关产品推荐
相关产品推荐

