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) { // 增加重启保护 while (!stoppingToken.IsCancellationRequested) { try { Console.WriteLine($"[NetMqSender] 连接至: {_target.Config.Endpoint}"); using var clientSocket = new PublisherSocket(); clientSocket.Options.SendHighWatermark = 1000; // 关键:增加 TCP 保活,防止防火墙静默断开长连接 clientSocket.Options.TcpKeepalive = true; clientSocket.Options.TcpKeepaliveIdle = TimeSpan.FromSeconds(5); clientSocket.Connect(_target.Config.Endpoint); int frameCount = 0; // 使用更稳健的读取方式 await foreach (var payload in _target.Channel.Reader.ReadAllAsync(stoppingToken)) { try { // 1. 构造消息 (内部执行了 MessagePack 序列化) var msg = payload.ToNetMqMessage(); // 2. 发送 bool sent = clientSocket.TrySendMultipartMessage(msg); if (!sent) { Console.WriteLine($"[NetMqSender] 发送缓冲区满,丢弃帧: {payload.CameraId}"); // ★ 如果没有发送成功,建议显式清理消息帧,防止内存滞留 msg.Clear(); } else { frameCount++; if (frameCount % 100 == 0) Console.WriteLine($"[NetMqSender] 已搬运 100 帧至缓冲区."); } } catch (Exception ex) { Console.WriteLine($"[NetMqSender] 内部循环异常: {ex.Message}"); } } } catch (OperationCanceledException) { break; } catch (Exception ex) { // ★★★ 核心改进:捕获异常并等待重试 ★★★ // 防止因为一次内存溢出或网络波动导致整个 BackgroundService 永久停止 Console.WriteLine($"[NetMqSender] 发生致命异常,5秒后尝试重建连接: {ex.Message}"); await Task.Delay(5000, stoppingToken); } finally { // 确保每次循环退出(无论是异常还是正常)都清理环境 NetMQConfig.Cleanup(false); } } } }