using Microsoft.Extensions.Hosting; using NetMQ; using NetMQ.Sockets; namespace SHH.CameraService; /// /// NetMQ 发送工作者 /// 职责:从指定目标的 VideoDataChannel 读取 Payload,通过 ZeroMQ 发送出去 /// public class NetMqSenderWorker : BackgroundService { private readonly StreamTarget _target; // 构造函数注入特定的目标对象 (由 Program.cs 的工厂方法提供) public NetMqSenderWorker(StreamTarget target) { _target = target; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { Console.WriteLine($"[NetMqSender] 正在连接至服务端: {_target.Config.Endpoint} ..."); // ★★★ 修正点:必须使用 PublisherSocket 来配合接收端的 SubscriberSocket ★★★ // 虽然是 Connect 模式,Publisher 依然可以 Connect using var clientSocket = new PublisherSocket(); // 设置高水位 (HWM) // 对于 Publisher,如果队列满了,默认行为就是丢弃旧数据,这非常符合视频流需求 clientSocket.Options.SendHighWatermark = 1000; // 主动连接 clientSocket.Connect(_target.Config.Endpoint); Console.WriteLine("[NetMqSender] 连接成功,开始从通道搬运数据..."); await foreach (var payload in _target.Channel.Reader.ReadAllAsync(stoppingToken)) { try { var msg = payload.ToNetMqMessage(); // 发送消息 // PublisherSocket 的 TrySend 如果没人订阅或者队列满了,通常不会阻塞,而是直接丢弃或返回 // 注意:PUB 模式下,第一帧 ("SHH_V1") 会被当作订阅的主题 (Topic)。 // 你的接收端订阅了 "" (空字符串),所以能收到以任何字符串开头的数据。 bool sent = clientSocket.TrySendMultipartMessage(msg); if (!sent) { // 这种情况通常意味着网络断了且 HWM 队列也满了 Console.WriteLine($"[NetMqSender] 警告: 发送队列已满,正在丢帧..."); msg.Clear(); // 手动清理(可选) } } catch (Exception ex) { Console.WriteLine($"[NetMqSender] 异常: {ex.Message}"); } } } }