C#控制台TCP服务迁移到Windows Service后客户端连接即崩溃问题求解
问题排查及解决方案
核心问题:服务实例被GC回收
你在Service1.OnStart方法中将MessageServer声明为局部变量,OnStart方法执行完成后,该实例没有任何存活的根引用,会被.NET垃圾回收器自动回收,实例持有的TCP监听线程也会被同步终止,所以客户端发起连接时服务就会停止运行。
DEBUG模式下你添加了Thread.Sleep(Timeout.Infinite)逻辑,会一直持有Service1实例引用,MessageServer不会被回收,因此运行正常。
其他潜在问题
- 监听逻辑未做异常捕获:
ListenForClientConnections方法内没有异常处理,任何序列化错误、IO错误都会直接终止监听线程,导致服务停止 - 未主动释放资源:客户端连接处理完成后没有主动释放
TcpClient和网络流资源,长期运行会出现资源泄漏 - 使用系统保留端口:515属于0-1023范围内的系统保留端口,部分运行环境下会出现端口占用、权限不足的问题
修复方案
1. 调整Service1的实例声明
将MessageServer改为类级字段,延长其生命周期和服务保持一致:
public partial class Service1 : ServiceBase { // 类级字段,避免被GC回收 private MessageServer _messageServer; public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { _messageServer = new MessageServer(515); _messageServer.Start(); } protected override void OnStop() { _messageServer?.Stop(); } }
2. 为监听逻辑添加异常捕获和资源释放
修改MessageServer.ListenForClientConnections方法:
private void ListenForClientConnections() { while (this._running) { try { this.connectedTcpClient = this._tcpListener.AcceptTcpClient(); using (var networkStream = connectedTcpClient.GetStream()) { Message1 message = (Message1)this._bFormatter.Deserialize(networkStream); Class1 c = new Class1(); // 原有业务逻辑保持不变 if (message.message == "AllRecipes") { List<Recipes2MP> recipes = c.GetAllRecipes(); _bFormatter.Serialize(networkStream, recipes); } // 其余else if逻辑保留 else if (message.message == "Exit") { Stop(); } } connectedTcpClient.Close(); connectedTcpClient.Dispose(); } catch (Exception ex) { // 可将日志写入系统事件日志或本地文件方便排查 Trace.WriteLine($"连接处理异常:{ex.Message}"); connectedTcpClient?.Close(); connectedTcpClient?.Dispose(); } } }
3. 可选优化
建议将监听端口改为1024以上的非保留端口(如5150),避免端口权限问题;如果需要允许非本机客户端访问,可将TcpListener初始化参数从IPAddress.Loopback改为IPAddress.Any。
内容的提问来源于stack exchange,提问作者Zubiczek
相关产品推荐
相关产品推荐

