2025-12-29 08:09:14 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using NetMQ;
|
|
|
|
|
|
using NetMQ.Sockets;
|
|
|
|
|
|
using SHH.Contracts;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SHH.NetMQ
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 视频分发服务端 (Publisher)
|
|
|
|
|
|
/// 特性:非阻塞、防内存溢出
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class DistributorServer : IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
private PublisherSocket _pubSocket;
|
|
|
|
|
|
private readonly object _lock = new object();
|
|
|
|
|
|
|
|
|
|
|
|
// 配置:高水位限制 (HWM)
|
|
|
|
|
|
// 假设 25fps,设置 50 意味着内存只缓存 2 秒的视频。
|
|
|
|
|
|
// 如果断网超过 2 秒,新来的视频帧直接丢弃,优先保证恢复后的实时性。
|
|
|
|
|
|
private const int HWM_LIMIT = 50;
|
|
|
|
|
|
|
|
|
|
|
|
public DistributorServer(string connectionString)
|
|
|
|
|
|
{
|
|
|
|
|
|
_pubSocket = new PublisherSocket();
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 设置发送缓冲区大小 (防爆内存关键)
|
|
|
|
|
|
_pubSocket.Options.SendHighWatermark = HWM_LIMIT;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 绑定地址 (如 tcp://*:5555)
|
|
|
|
|
|
_pubSocket.Bind(connectionString);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Broadcast(VideoPayload payload)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (payload == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 补充发送时间
|
2026-01-07 10:59:03 +08:00
|
|
|
|
payload.DispatchTimestamp = DateTime.Now.Ticks;
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 准备数据帧
|
|
|
|
|
|
string jsonMeta = payload.GetMetadataJson();
|
|
|
|
|
|
byte[] rawBytes = payload.OriginalImageBytes ?? new byte[0];
|
|
|
|
|
|
byte[] targetBytes = payload.TargetImageBytes ?? new byte[0];
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 NetMQMessage 封装多帧消息
|
|
|
|
|
|
// 这样比手动调三次 Send 更容易管理原子性
|
|
|
|
|
|
var msg = new NetMQMessage();
|
|
|
|
|
|
msg.Append(jsonMeta); // 第1帧
|
|
|
|
|
|
msg.Append(rawBytes); // 第2帧
|
|
|
|
|
|
msg.Append(targetBytes); // 第3帧
|
|
|
|
|
|
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 3. 非阻塞发送 (核心防卡死代码)
|
|
|
|
|
|
// TimeSpan.Zero 表示:如果缓冲区满了或者发不出去,立即放弃,不等待,返回 false
|
|
|
|
|
|
// 这样你的主线程(海康SDK回调)永远不会被卡住
|
|
|
|
|
|
bool sent = _pubSocket.TrySendMultipartMessage(TimeSpan.Zero, msg);
|
|
|
|
|
|
|
|
|
|
|
|
if (!sent)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 这里可以打个日志:Console.WriteLine("警告:网络拥堵,丢帧中...");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
_pubSocket?.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|