在SignalR中使服务器端客户端列表线程安全

本文关键字:列表 线程 安全 客户端 服务器端 SignalR | 更新日期: 2023-09-27 18:21:15

我正在努力确保服务器端线程的安全。

目前,我正在使用List<ServerClient> m_connectedClients,当我的客户连接或断开连接时,我会用它填充,如下所示:

    public LoginStatus Connect(string connectionId, LoginRequestMessage message)
    {
        var status = m_databaseManager.CheckLogin(message.Username, message.Password);
        if (status == LoginStatus.Success)
        {
            var connection = m_connectedClients.FirstOrDefault(p => p.Username == message.Username);
            if (connection == null)
            {
                var client = m_databaseManager.GetClient(message.Username, connectionId);
                m_connectedClients.Add(client);
            }
            else if (!connection.ConnectionIds.Contains(connectionId))
            {
                connection.ConnectionIds.Add(connectionId);
            }
        }
        return status;
    }
    public void Disconnect(string connectionId)
    {
        foreach (var connection in m_connectedClients.Where(p => p.ConnectionIds.Contains(connectionId)))
        {
            connection.ConnectionIds.Remove(connectionId);
        }
        Console.WriteLine("Client disconnected... {0}", connectionId);
    }

在我的场景中,在某些情况下,我想做这样的事情:

    public bool IsLoggedIn(string connectionId)
    {
        if (m_connectedClients.Any(p => p.ConnectionIds.Contains(connectionId)))
        {
            return true;
        }
        return false;
    }

因此,简单地用ConcurrentDictionary添加和删除内容可能不会起作用(我甚至不知道我会使用什么密钥,因为我每个客户端可能有多个ConnectionId,这是我在这里唯一的标识符。

我可以做的是每次访问List<ServerClient>时都锁定它,但这会发生在很多有很多锁的地方,所以我想这是一个糟糕的主意,对吧?

另一个问题是:我必须在任何地方都保持线程安全吗?还是仅在连接(添加)和断开连接(删除)时才重要,而在实际使用该列表时不重要?

在SignalR中使服务器端客户端列表线程安全

因此,简单地用ConcurrentDictionary添加和删除内容可能不会起作用(我甚至不知道我会使用什么密钥,因为我每个客户端可能有多个ConnectionId,这是我在这里唯一的标识符。

你是对的。ConcurrentDictionary对于您的用例来说可能过于有限。

我可以做的是每次访问列表时都锁定它,但这会在很多有很多锁的地方发生,所以我想这是一个糟糕的主意,对吧?

这是没有办法的:每次你访问列表时,你都应该带上一把锁。创建一个提供所需列表的功能的类,并将锁和获取锁放在那里,这样获取锁就不会分散在代码中,可能会被意外遗忘。

另一个问题是:我在任何地方都必须是线程安全的吗?还是仅在连接(添加)和断开连接(删除)时才重要,而在实际使用该列表时不重要?

线程安全是一个全局特性。如果你不是处处都是线程安全的,那么你就不是线程安全期。如果您有很多读卡器和读取操作,而只有很少的写入器和写入操作,那么可以考虑使用针对此类场景优化的ReaderWriterLockSlim类。不过,每次访问列表时都必须使用它。