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

示例中作为TCP套接字服务器的Worker Service如何正确关闭

问题根因
  • 核心原因1:clientServer.start方法未关联服务停止的取消令牌,TCP监听逻辑处于永久阻塞状态。当服务收到停止指令时,ExecuteAsync无法跳出阻塞响应stoppingToken的取消信号,宿主等待超时后会强制终止进程,StopAsync方法没有执行机会,Socket资源未被释放。
  • 核心原因2:Socket实例作用域混乱,Main方法中提前创建了无用的Socket实例占用端口,Worker类中又单独创建了新的SocketConnection实例,两处Socket实例没有统一管理。
  • 辅助原因:服务未初始化成功时,ExecuteAsync会进入无延迟的空跑死循环,占用CPU资源的同时也会影响停止信号的响应。
修复方案

1. 清理无效Socket初始化

删除Main方法中提前创建的无用Socket实例,避免提前占用目标端口:

public static void Main(string[] args)
{
    Log log = new();
    // 移除该行无用的Socket创建逻辑
    // Socket socket = new SocketConnection().getSocket();
    try
    {
        DataStorage.Instance.osPlatform = RuntimeInformation.OSDescription;
        if (DataStorage.Instance.osPlatform.Contains("Win"))
        {
            Console.WriteLine("WinOS");
            CreateHostBuilderWin(args).Build().Run();
        }
        else
        {
            Console.WriteLine("MacOS");
            CreateHostBuilderMac(args).Build().Run();
        }
    }
    catch (Exception ex)
    {
        log.write("Could not start SDS. ", ex);
    }
    
    log.write("Program is reached on shutdown", null);
}

2. 改造clientServer.start方法支持取消信号

给start方法新增CancellationToken入参,监听逻辑中关联取消令牌,收到停止信号时自动跳出阻塞:

// clientServer.start方法改造示例
public async Task start(Socket listener, CancellationToken stoppingToken)
{
    // 开启端口复用,避免异常退出后端口占用
    listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    listener.Listen();
    while (!stoppingToken.IsCancellationRequested)
    {
        // 使用支持取消令牌的AcceptAsync重载
        var client = await listener.AcceptAsync(stoppingToken);
        // 原有客户端处理逻辑
    }
}

3. 优化Worker执行逻辑,增加资源释放双保险

在ExecuteAsync中传入取消令牌、增加异常延迟,同时在finally块中补充Socket释放逻辑,和StopAsync形成双重保障:

protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
    try{
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                if (DataStorage.Instance.sdsInitialized)
                {
                    log.write("startasync is reached", null);
                    listener = socket.getSocket();
                    log.write("Socket: " + listener.AddressFamily + " " + listener.RemoteEndPoint, null);
                    // 传入停止取消令牌
                    await clientServer.start(listener, stoppingToken);
                }
                else
                {
                    log.write("Sds not initialized properly", null);
                    // 增加延迟避免空跑循环
                    await Task.Delay(1000, stoppingToken);
                }
            }
            catch (OperationCanceledException)
            {
                log.write("Service cancellation requested, exiting", null);
                break;
            }
            catch (Exception ex)
            {
                log.write("Could not create Socket for server", ex);
                // 异常后增加延迟避免崩溃循环
                await Task.Delay(3000, stoppingToken);
            }
        }

    }
    finally
    {
        log.write("Finally reached, releasing socket resource", null);
        // 补充释放逻辑,双保险
        if (listener != null)
        {
            EndSDS endSDS = new EndSDS();
            endSDS.start(listener);
        }
        _hostApplicationLifetime.StopApplication();
    }
}

内容的提问来源于stack exchange,提问作者Kim Sandberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:36:00