Files
Ayay/SHH.CameraService/Core/NetSenders/NetMqSenderWorker.cs

84 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Hosting;
using NetMQ;
using NetMQ.Sockets;
namespace SHH.CameraService;
/// <summary>
/// NetMQ 发送工作者
/// 职责:从指定目标的 VideoDataChannel 读取 Payload通过 ZeroMQ 发送出去
/// </summary>
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);
}
}
}
}