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

如何在.NET Core中用游戏循环触发SignalR群组消息?

.NET Core SignalR 实现GameRoom定时自动广播方案

核心替代方案

在.NET Core SignalR中,不再使用GlobalHost获取Hub上下文,而是通过依赖注入(DI)注入IHubContext<GameHub>,让GameRoom直接持有上下文实例来发送群组消息,这是符合.NET Core设计规范的标准做法。

具体实现步骤与代码示例

1. 重构GameRoom,注入IHubContext

将IHubContext<GameHub>通过构造函数注入到GameRoom中,替代原来的GlobalHost方式。同时推荐使用.NET 6+引入的PeriodicTimer(异步友好,避免传统Timer的线程问题)实现5秒循环:

public class GameRoom
{
    private readonly IHubContext<GameHub> _hubContext;
    private readonly List<Player> _players;
    private readonly Scoreboard _scores;
    private readonly string _gameRoomName;
    private PeriodicTimer _gameLoopTimer;

    // 构造函数注入IHubContext
    public GameRoom(IHubContext<GameHub> hubContext, string gameRoomName)
    {
        _hubContext = hubContext;
        _gameRoomName = gameRoomName;
        _players = new List<Player>();
        _scores = new Scoreboard();
    }

    // 启动异步游戏循环
    public async Task StartGameLoopAsync(CancellationToken cancellationToken = default)
    {
        _gameLoopTimer = new PeriodicTimer(TimeSpan.FromSeconds(5));
        try
        {
            while (await _gameLoopTimer.WaitForNextTickAsync(cancellationToken))
            {
                // 组装当前游戏状态数据
                var gameState = GetCurrentGameState();
                // 向对应群组广播消息
                await _hubContext.Clients.Group(_gameRoomName).SendAsync("ReceiveGameState", gameState);
            }
        }
        catch (OperationCanceledException)
        {
            // 处理房间关闭时的取消逻辑
        }
        finally
        {
            // 释放Timer资源
            await _gameLoopTimer.DisposeAsync();
        }
    }

    // 停止游戏循环
    public void StopGameLoop()
    {
        _gameLoopTimer?.Dispose();
    }

    // 获取当前游戏状态(自定义实现)
    private GameState GetCurrentGameState()
    {
        return new GameState
        {
            Scoreboard = _scores,
            Players = _players,
            RoomName = _gameRoomName
        };
    }
}

2. 在GameHub中管理GameRoom

在GameHub中通过DI获取IHubContext<GameHub>,创建GameRoom时将上下文传递进去,并处理房间的生命周期:

public class GameHub : Hub
{
    private readonly IHubContext<GameHub> _hubContext;
    private readonly List<GameRoom> _gameRooms;

    // 注入IHubContext用于创建GameRoom
    public GameHub(IHubContext<GameHub> hubContext)
    {
        _hubContext = hubContext;
        _gameRooms = new List<GameRoom>();
    }

    // 示例:创建游戏房间的方法
    public async Task CreateGameRoom(string roomName)
    {
        var existingRoom = _gameRooms.FirstOrDefault(r => r.RoomName == roomName);
        if (existingRoom != null)
        {
            await Clients.Caller.SendAsync("RoomExists", roomName);
            return;
        }

        var newRoom = new GameRoom(_hubContext, roomName);
        _gameRooms.Add(newRoom);
        // 将当前连接加入房间群组
        await Groups.AddToGroupAsync(Context.ConnectionId, roomName);
        // 启动房间的定时广播循环
        await newRoom.StartGameLoopAsync();
        await Clients.Caller.SendAsync("RoomCreated", roomName);
    }

    // 示例:玩家退出房间时的清理逻辑
    public override async Task OnDisconnectedAsync(Exception exception)
    {
        // 找到当前连接所在的房间,处理玩家退出、房间销毁等逻辑
        // ...
        await base.OnDisconnectedAsync(exception);
    }
}

关键说明

  • 异步优先:使用PeriodicTimer配合async/await,避免传统System.Timers.Timer的线程池线程问题,更适配.NET Core的异步生态。
  • 生命周期管理:房间关闭或玩家全部退出时,务必调用StopGameLoop释放PeriodicTimer,防止内存泄漏。
  • 依赖注入优势:通过DI获取IHubContext,符合.NET Core的控制反转原则,便于测试和扩展。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:35:35