using System.Collections.Concurrent; using Microsoft.Extensions.Hosting; using NetMQ; using NetMQ.Sockets; using MessagePack; using SHH.CameraSdk; using SHH.Contracts; using System.Text; namespace SHH.CameraService { public class DeviceStateMonitorWorker : BackgroundService { private readonly CameraManager _manager; private readonly ServiceConfig _config; private readonly InterceptorPipeline _pipeline; // 修改点1: 改为 Socket 列表 private readonly List _sockets = new(); private readonly ConcurrentDictionary _stateStore = new(); private volatile bool _isDirty = false; private long _lastSendTick = 0; public DeviceStateMonitorWorker( CameraManager manager, ServiceConfig config, InterceptorPipeline pipeline) { _manager = manager; _config = config; _pipeline = pipeline; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 1. 初始化 foreach (var dev in _manager.GetAllDevices()) { UpdateLocalState(dev.Id, false, "Init"); } _manager.OnDeviceStatusChanged += OnSdkStatusChanged; // 修改点2: 遍历所有端点建立连接 if (_config.CommandEndpoints.Count == 0) return; Console.WriteLine($"[StatusWorker] 启动状态上报,目标节点数: {_config.CommandEndpoints.Count}"); foreach (var ep in _config.CommandEndpoints) { try { var socket = new DealerSocket(); // 状态通道也建议设置 Identity,方便服务端追踪 socket.Options.Identity = Encoding.UTF8.GetBytes(_config.AppId + "_status"); socket.Options.SendHighWatermark = 1000; socket.Connect(ep.Uri); _sockets.Add(socket); } catch (Exception ex) { Console.WriteLine($"[StatusWorker] 连接失败 {ep.Uri}: {ex.Message}"); } } // 定时循环 (1秒1次) var timer = new PeriodicTimer(TimeSpan.FromSeconds(1)); try { while (await timer.WaitForNextTickAsync(stoppingToken)) { await CheckAndBroadcastAsync(); } } finally { _manager.OnDeviceStatusChanged -= OnSdkStatusChanged; // 清理所有 socket foreach (var s in _sockets) s.Dispose(); } } private void OnSdkStatusChanged(long deviceId, bool isOnline, string reason) { UpdateLocalState(deviceId, isOnline, reason); _isDirty = true; } private void UpdateLocalState(long deviceId, bool isOnline, string reason) { var evt = new StatusEventPayload { CameraId = deviceId.ToString(), IsOnline = isOnline, Reason = reason, Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }; _stateStore[deviceId.ToString()] = evt; } // 修改点3: 广播发送逻辑 private async Task CheckAndBroadcastAsync() { long now = Environment.TickCount64; // 策略: 有变更 或 超过5秒(心跳) bool shouldSend = _isDirty || (now - _lastSendTick > 5000); if (shouldSend && _sockets.Count > 0) { try { var snapshot = _stateStore.Values.ToList(); var batch = new StatusBatchPayload { Items = snapshot, Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }; byte[] data = MessagePackSerializer.Serialize(batch); // 拦截器处理 var ctx = await _pipeline.ExecuteSendAsync("STATUS_BATCH", data); if (ctx != null) { // ★★★ 核心修复:循环广播给所有 Socket ★★★ foreach (var socket in _sockets) { // TrySend 避免阻塞,如果某个服务端卡死不影响其他端 socket.SendMoreFrame(ctx.Protocol).TrySendFrame(ctx.Data); } _isDirty = false; _lastSendTick = now; } } catch (Exception ex) { Console.WriteLine($"[StatusWorker] 发送失败: {ex.Message}"); } } } } }