/// <summary> /// 构造器 /// </summary> /// <param name="roomIds">要监控的房间ID数组</param> public DanmuMonitor(uint[] roomIds) { if (roomIds == null) { throw new ArgumentNullException(nameof(roomIds)); } _roomIds = roomIds; _clients = new TcpClient[_roomIds.Length]; for (int i = 0; i < _clients.Length; i++) { _clients[i] = new TcpClient(); } _isConnecteds = new bool[_roomIds.Length]; _connectionKeeper = new Thread(() => SafeCaller.Loop(KeepConnection)) { IsBackground = true, Name = "DanmuMonitor.ConnectionKeeper" }; _heartBeatSender = new Thread(() => SafeCaller.Loop(SendHeartBeat)) { IsBackground = true, Name = "DanmuMonitor.HeartBeatSender" }; _danmuHandler = new Thread(() => SafeCaller.Loop(HandleDanmu)) { IsBackground = true, Name = "DanmuMonitor.DanmuHandler" }; _cachedCheckRead = new List <Socket>(_clients.Length); }
private void KeepConnection() { List <TcpClient> unconnectedClients; int[] unconnectedClientIndexMap; unconnectedClients = new List <TcpClient>(_clients.Length); unconnectedClientIndexMap = new int[_clients.Length]; while (true) { int connectedCount; for (int i = 0; i < _clients.Length; i++) { if (!_isConnecteds[i]) { unconnectedClientIndexMap[unconnectedClients.Count] = i; // 将TcpClient在unconnectedClients中的索引转换到_clients中的索引 unconnectedClients.Add(_clients[i]); } } if (unconnectedClients.Count == 0) { // 所有客户端都连接到了服务器 goto sleep; } GlobalSettings.Logger.LogInfo($"检测到 {unconnectedClients.Count} 个客户端处于离线状态"); connectedCount = 0; if (unconnectedClients.Count > 50) { // 如果未连接客户端过多就并行处理 Parallel.For(0, unconnectedClients.Count, i => { if (SafeCaller.Call(() => ConnectAndEnterRoom(unconnectedClients, i), true)) { Interlocked.Increment(ref connectedCount); _isConnecteds[unconnectedClientIndexMap[i]] = true; } }); } else { for (int i = 0; i < unconnectedClients.Count; i++) { if (SafeCaller.Call(() => ConnectAndEnterRoom(unconnectedClients, i), true)) { connectedCount++; _isConnecteds[unconnectedClientIndexMap[i]] = true; } } } GlobalSettings.Logger.LogInfo($"{connectedCount} 个客户端成功连接到弹幕服务器"); unconnectedClients.Clear(); sleep: Thread.Sleep(1000); // 1秒检查一次 TODO: 延时时间加入配置文件 } }