84 lines
3.2 KiB
C#
84 lines
3.2 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|
||
} |