获取连接到SignalR Hub的监听器和客户端数量

67

有没有一种方法可以找出听众的数量(连接到中心的客户端)?

我正在尝试运行/启动一个任务,如果至少有一个客户端连接,则启动它,否则不启动:

[HubName("taskActionStatus")]
public class TaskActionStatus : Hub, IDisconnect
{
    static CancellationTokenSource tokenSource;

    public void GetTasksStatus(int? siteId)
    {
        tokenSource = new CancellationTokenSource();
        CancellationToken ct = tokenSource.Token;

        ITaskRepository taskRepository = UnityContainerSetup.Container.Resolve<ITaskRepository>();

        // init task for checking task statuses
        var tasksItem = new DownloadTaskItem();
        taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);

        // subscribe to event [ listener ]
        tasksItem.Changed += new EventHandler<TaskEventArgs>(UpdateTasksStatus);
    }

    public void UpdateTasksStatus(object sender, TaskEventArgs e)
    {
        Clients.updateMessages(e.Tasks);
    }

    // when browsing away from page
    public Task Disconnect()
    {
        try
        {
            tokenSource.Cancel();
        }
        catch (Exception)
        {
            //
        }

        return null;
    }
}

谢谢


请查看https://dev59.com/Ieo6XIcBkEYKwwoYKRHd#21070978 - KRoy
6个回答

117

在SignalR中没有办法直接获取这个计数。您需要使用Hub上的OnConnect()OnDisconnect()方法来自行维护计数。

下面是一个使用静态类来保存计数的简单示例:

public static class UserHandler
{
    public static HashSet<string> ConnectedIds = new HashSet<string>();
}

public class MyHub : Hub
{
    public override Task OnConnectedAsync()
    {
        UserHandler.ConnectedIds.Add(Context.ConnectionId);
        return base.OnConnectedAsync();
    }

    public override Task OnDisconnectedAsync(Exception exception)
    {
        UserHandler.ConnectedIds.Remove(Context.ConnectionId);
        return base.OnDisconnectedAsync(exception);
    }
}

然后你可以从UserHandler.ConnectedIds.Count获取计数。


7
+1 只需记住,在应用程序域重新启动时,该对象将被重置;您应该考虑在某个时刻持久化该对象;我通常在每次添加或删除某人时都会这样做。 - cillierscharl
19
如果您只运行一个服务器,那么像这样使用静态类是可行的,但如果您在云中,并且在多个服务器之间使用负载均衡器,那么这种解决方案就会失败。但是您可以使用缓存服务器来存储连接的用户。我们使用 Azure 托管的 Redis。 - Anj
1
@Anj SignalR本身运行的服务器,即应用程序服务器。这不是你最大的担忧,但确实是一个担忧。你可以保存有关侦听器的更多信息,而不仅仅是计数器,并实现应用程序级心跳以删除孤立的客户端。然而,实际上这样的信息必须存在于SignalR中,但(正如微软所说)由于设计原因,你无法查询它。 - Niklas Peter
8
不要忘记在SignalR 2.2.1中覆盖OnReconnected。如果客户端使用相同的connection_id重新连接,则不会调用OnConnect。 - Yan Oreshchenkov
7
“static HashSet<string> ConnectedIds” 看起来完全不具备线程安全性。 - Pang
显示剩余10条评论

29

对于版本2.1.1<,应该是:

public static class UserHandler
{
    public static HashSet<string> ConnectedIds = new HashSet<string>();
}

public class MyHub : Hub
{
    public override Task OnConnected()
    {
        UserHandler.ConnectedIds.Add(Context.ConnectionId);
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        UserHandler.ConnectedIds.Remove(Context.ConnectionId);
        return base.OnDisconnected(stopCalled);
    }
}

3
在进行服务器分片时要小心。最好使用缓存或数据库来存储你的中心数据。 - Nigrimmist
请注意,如果您的服务器应用程序在Azure中运行并且进行垂直扩展,则此方法将无法使用。您需要一个共享缓存,例如Redis或SQL/NoSQL数据库(或任何其他共享资源)来跟踪连接。 - Andy
1
现在你需要使用 OnConnectedAsync 和 OnDisconnectedAsync。 - kofifus
3
据我所知,HasSet不是线程安全的,因此我认为在访问ConnectedIds时需要进行一些同步。 - teroplut

10
在SignalR(版本2.4.1)中,这相当容易:
public int GetOnline()
{
   return GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>().GetConnections().Count;
}

只需从客户端调用此方法(:


6

现在你需要:

public override Task OnConnectedAsync()
{
    UserHandler.ConnectedIds.Add(Context.ConnectionId);

    return base.OnConnectedAsync();
}

public override Task OnDisconnectedAsync(Exception exception)
{
    UserHandler.ConnectedIds.Remove(Context.ConnectionId);
    return base.OnDisconnectedAsync(exception);
}

3
在我看来,也许你应该编辑已接受的答案而不是添加新的答案?这样可以使线程更清洁,减少答案数量。此外,人们更有可能选择第一个(在这种情况下是已接受的)答案。 - LuvForAirplanes

1

0

在我的项目中,使用的是Microsoft.AspNetCore.SignalR.Core版本1.1.0

我可以使用以下代码进行调试并查看计数:

((Microsoft.AspNetCore.SignalR.DefaultHubLifetimeManager<XXX.Push.SignalR.EventHub>)((Microsoft.AspNetCore.SignalR.Internal.AllClientProxy<XXX.Push.SignalR.EventHub>)((Microsoft.AspNetCore.SignalR.TypedClientBuilder.IEventImpl)((Microsoft.AspNetCore.SignalR.Internal.HubClients<XXX.Push.SignalR.EventHub, XXX.Push.SignalR.IEvent>)_hub.Clients).All)._proxy)._lifetimeManager)._connections.Count

它看起来像这样:

debug


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接