using Microsoft.Extensions.Hosting; using NetMQ; using NetMQ.Sockets; using Newtonsoft.Json; using SHH.CameraSdk; using System.Text; namespace SHH.CameraService; public class CommandClientWorker : BackgroundService { private readonly ServiceConfig _config; public CommandClientWorker(ServiceConfig config) { _config = config; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { // 1. 如果不是主动/混合模式,不需要连接 if (!_config.ShouldConnect) return; // ★★★ 核心修正:直接读取解析好的指令地址列表 ★★★ // 这些地址来自参数 --uris "IP,VideoPort&CommandPort" 中的 CommandPort 部分 var cmdUris = _config.CommandEndpoints; if (cmdUris.Count == 0) { Console.WriteLine("[指令] 未在参数中找到指令通道地址(位于&符号右侧),跳过连接。"); return; } // 2. 初始化 Dealer Socket using var dealer = new DealerSocket(); // 设置身份 (Identity),让 Dashboard 知道我是 "CameraApp_01" string myIdentity = _config.AppId; dealer.Options.Identity = Encoding.UTF8.GetBytes(myIdentity); // 3. 连接所有目标 (支持多点控制) foreach (var uri in cmdUris) { Console.WriteLine($"[指令] 连接控制端: {uri}"); dealer.Connect(uri); } // 4. 发送登录包 (握手) // 构造心跳包 var heartbeat = new { Type = "Login", Id = myIdentity, Time = DateTime.Now }; string loginJson = JsonConvert.SerializeObject(heartbeat); // 注意:Dealer Socket 发送是负载均衡的 (Round-Robin)。 // 如果连接了多个 Dashboard,SendFrame 一次只会发给其中一个。 // 为了确保所有 Dashboard 都能收到上线通知,我们根据连接数循环发送几次。 // (注:这只是初始化时的权宜之计,心跳包后续可以定时发送) for (int i = 0; i < cmdUris.Count; i++) { dealer.SendFrame(loginJson); await Task.Delay(10); // 稍微间隔,给 ZMQ 内部调度一点时间 } Console.WriteLine($"[指令] 已发送登录包 (ID: {myIdentity}),进入监听循环..."); // 5. 监听循环 while (!stoppingToken.IsCancellationRequested) { try { // 非阻塞接收 (500ms 超时),避免卡死线程 if (dealer.TryReceiveFrameString(TimeSpan.FromMilliseconds(500), out string msg)) { Console.WriteLine($"[指令] 收到: {msg}"); // TODO: 在这里解析 JSON 并调用 CameraSDK 执行业务 // var cmd = JsonConvert.DeserializeObject(msg); // if (cmd.Action == "Reboot") ... // 回复 ACK (确认收到) // Dealer 会自动根据 Router 发来的 RoutingID 路由回去 dealer.SendFrame($"ACK: {msg} (From {myIdentity})"); } } catch (Exception ex) { Console.WriteLine($"[指令] 通信异常: {ex.Message}"); // 防止异常死循环刷屏 await Task.Delay(1000, stoppingToken); } } } }