You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:30:03