优化 Mjpeg 播放

This commit is contained in:
2026-01-22 14:06:44 +08:00
parent c438edfa0d
commit 6661edfc44
4 changed files with 111 additions and 105 deletions

View File

@@ -47,30 +47,26 @@ namespace SHH.MjpegPlayer
try try
{ {
var process = Process.GetProcessById(pid); var process = Process.GetProcessById(pid);
if (process != null) if (process != null)
{ {
procName = process.ProcessName; procName = process.ProcessName;
process.Kill(); process.Kill();
_sysLog.Warning("拒绝停止高权限系统进程: {Pid} - {Name}", pid, process.ProcessName); _sysLog.Information("成功通过 PID 杀掉进程 - Pid: {Pid}, Name: {Name}", pid, procName);
return true; return true;
} }
else
{ _sysLog.Warning("无法获取进程实例 - Pid: {Pid}", pid);
// 找不到 ID 对应的进程,应该是进异常不会进这里 return false;
_sysLog.Information("成功杀掉进程 - Pid: {Pid}", pid);
return false;
}
} }
catch (ArgumentException) catch (ArgumentException)
{ {
_sysLog.Warning("杀掉进程失败Pid: {Pid} 不存在", pid); _sysLog.Warning("杀掉进程失败Pid: {Pid} 不存在或已提前退出", pid);
return false; return false;
} }
catch (Exception ex) catch (Exception ex)
{ {
_sysLog.Error(ex, "杀掉进程异常, Pid: {Pid}", pid); _sysLog.Error(ex, "杀掉进程异常, Pid: {Pid}, 进程名: {Name}", pid, procName);
return false; return false;
} }
} }

View File

@@ -65,123 +65,112 @@ namespace SHH.MjpegPlayer
/// <summary> /// <summary>
/// 刷新方法调用次数 /// 刷新方法调用次数
/// </summary> /// </summary>
/// <param name="logger"></param>
/// <param name="methodName"></param> /// <param name="methodName"></param>
/// <param name="count"></param> /// <param name="count"></param>
public void Refresh(string methodName, uint count = 1) public void Refresh(string methodName, uint count = 1)
{ {
try try
{ {
#region #region
// 加入集合
lock (_second) lock (_second)
{ {
// 确保键存在
if (!_second.ContainsKey(methodName)) if (!_second.ContainsKey(methodName))
_second.Add(methodName, 0); _second.Add(methodName, 0);
if (!LastRefreshSecond.Equals(DateTime.Now.Second))
{
LastRefreshSecond = DateTime.Now.Second;
// 获取当前键的快照进行遍历,确保线程安全
var keys = _second.Keys.ToList();
foreach (var key in keys)
{
uint val = _second[key];
if (!TotalSecond.ContainsKey(key))
TotalSecond.Add(key, val);
else
TotalSecond[key] = val;
_second[key] = 0; // 重置当前秒计数值
}
}
_second[methodName] += count;
} }
// 加入集合 #endregion
#region
lock (_minute) lock (_minute)
{ {
if (!_minute.ContainsKey(methodName)) if (!_minute.ContainsKey(methodName))
_minute.Add(methodName, 0); _minute.Add(methodName, 0);
if (!LastRefreshMinute.Equals(DateTime.Now.Minute))
{
LastRefreshMinute = DateTime.Now.Minute;
var keys = _minute.Keys.ToList();
foreach (var key in keys)
{
uint val = _minute[key];
if (!TotalMinute.ContainsKey(key))
TotalMinute.Add(key, val);
else
TotalMinute[key] = val;
_minute[key] = 0;
}
}
_minute[methodName] += count;
} }
#endregion
#region
lock (_hour) lock (_hour)
{ {
if (!_hour.ContainsKey(methodName)) if (!_hour.ContainsKey(methodName))
_hour.Add(methodName, 0); _hour.Add(methodName, 0);
if (!LastRefreshHour.Equals(DateTime.Now.Hour))
{
LastRefreshHour = DateTime.Now.Hour;
var keys = _hour.Keys.ToList();
foreach (var key in keys)
{
uint val = _hour[key];
if (!TotalHour.ContainsKey(key))
TotalHour.Add(key, val);
else
TotalHour[key] = val;
_hour[key] = 0;
}
}
_hour[methodName] += count;
} }
// 加入集合 #endregion
#region
lock (All) lock (All)
{ {
if (!All.ContainsKey(methodName)) if (!All.ContainsKey(methodName))
All.Add(methodName, 0); All.Add(methodName, 0);
All[methodName] += (ulong)count;
} }
#endregion #endregion
#region
// 秒刷新
if (!LastRefreshSecond.Equals(DateTime.Now.Second))
{
LastRefreshSecond = DateTime.Now.Second;
var sb = new StringBuilder();
foreach (var de in _second)
{
// 更新输出用统计信息
if (!TotalSecond.ContainsKey(de.Key))
TotalSecond.Add(de.Key, de.Value);
else
TotalSecond[de.Key] = de.Value;
sb.Append($"\r\n\t{de.Key} => 执行 {de.Value} 次");
_second[de.Key] = 0;
}
var logMsg = $"统计 => SumBySecond 统计时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}{sb.ToString()}";
//Logs.LogInformation<SumByTime>(EIdSys.TotalBySecond, logMsg);
}
// 分钟刷新
if (!LastRefreshMinute.Equals(DateTime.Now.Minute))
{
LastRefreshMinute = DateTime.Now.Minute;
var sb = new StringBuilder();
foreach (var de in _minute)
{
// 更新输出用统计信息
if (!TotalMinute.ContainsKey(de.Key))
TotalMinute.Add(de.Key, de.Value);
else
TotalMinute[de.Key] = de.Value;
sb.Append($"\r\n\t{de.Key} => 执行 {de.Value} 次, 平均每秒 {Math.Round((double)de.Value / 60, 2)} 次");
_minute[de.Key] = 0;
}
var logMsg = $"统计 => SumByMinute 统计时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}{sb.ToString()}";
//Logs.LogInformation<SumByTime>(EIdSys.TotalByMinute, logMsg);
}
// 小时刷新
if (!LastRefreshHour.Equals(DateTime.Now.Hour))
{
LastRefreshHour = DateTime.Now.Hour;
var sb = new StringBuilder();
foreach (var de in _hour)
{
// 更新输出用统计信息
if (!TotalHour.ContainsKey(de.Key))
TotalHour.Add(de.Key, de.Value);
else
TotalHour[de.Key] = de.Value;
sb.Append($"\r\n\t{de.Key} => 执行 {de.Value} 次, 平均每秒 {Math.Round((double)de.Value / 60, 2)} 次");
_hour[de.Key] = 0;
}
var logMsg = $"统计 => SumByHour 统计时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}{sb.ToString()}";
//Logs.LogInformation<SumByTime>(EIdSys.TotalByHour, logMsg);
}
#endregion
#region
_second[methodName] += count;
_minute[methodName] += count;
_hour[methodName] += count;
All[methodName] += count;
#endregion
} }
catch (Exception ex) catch (Exception ex)
{ {
//Logs.LogWarning<SumByTime>(ex.Message); // 可选:利用 Ayay 项目规范记录日志
// _sysLog.Warning("统计刷新异常: {Msg}", ex.Message);
} }
} }

View File

@@ -7,6 +7,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Bat\**" />
<EmbeddedResource Remove="Bat\**" />
<None Remove="Bat\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CoreWCF.Http" Version="1.8.0" /> <PackageReference Include="CoreWCF.Http" Version="1.8.0" />
<PackageReference Include="CoreWCF.Primitives" Version="1.8.0" /> <PackageReference Include="CoreWCF.Primitives" Version="1.8.0" />

View File

@@ -13,16 +13,20 @@ namespace SHH.MjpegPlayer
/// </summary> /// </summary>
public class MjpegSession : IDisposable public class MjpegSession : IDisposable
{ {
#region Defines
private static readonly ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core); private static readonly ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core);
#region Counter private CancellationTokenSource? _sessionCts;
private SumByTime _sumBySecond = new SumByTime(); private SumByTime _sumBySecond = new SumByTime();
/// <summary>
/// 计数器 /// <summary>计数器</summary>
/// </summary>
public SumByTime Counter => _sumBySecond; public SumByTime Counter => _sumBySecond;
// 引入 Disposed 标志位
private volatile bool _isDisposed = false;
#endregion #endregion
#region Info #region Info
@@ -43,9 +47,6 @@ namespace SHH.MjpegPlayer
#endregion #endregion
// [修复] 引入 Disposed 标志位
private volatile bool _isDisposed = false;
#region Constructor #region Constructor
/// <summary> /// <summary>
@@ -150,7 +151,10 @@ namespace SHH.MjpegPlayer
// 初始化最近接收时间,避免刚连接就被判定为超时 // 初始化最近接收时间,避免刚连接就被判定为超时
LastRecImgTime = DateTime.Now; LastRecImgTime = DateTime.Now;
Task.Run(() => { DoWorkTask(client); }); // 绑定全局取消令牌,确保系统停止时能立即强制中断所有会话
_sessionCts = new CancellationTokenSource();
Task.Run(() => { DoWorkTask(client, _sessionCts.Token); }, _sessionCts.Token);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -162,7 +166,7 @@ namespace SHH.MjpegPlayer
#region DoWorkTask #region DoWorkTask
private void DoWorkTask(TcpClient client) private void DoWorkTask(TcpClient client, CancellationToken token)
{ {
try try
{ {
@@ -174,11 +178,12 @@ namespace SHH.MjpegPlayer
#region , #region ,
int iLoc = 0; int iLoc = 0;
while (!client.Connected) while (!client.Connected && !token.IsCancellationRequested)
{ {
Thread.Sleep(50); Thread.Sleep(50);
if (++iLoc > 60) return; if (++iLoc > 60) return;
} }
if (token.IsCancellationRequested) return;
try try
{ {
@@ -210,7 +215,7 @@ namespace SHH.MjpegPlayer
byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--frame\r\nContent-Type: image/jpeg\r\nContent-Length: "); byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--frame\r\nContent-Type: image/jpeg\r\nContent-Length: ");
byte[] doubleNewLine = Encoding.ASCII.GetBytes("\r\n\r\n"); byte[] doubleNewLine = Encoding.ASCII.GetBytes("\r\n\r\n");
while (client.Connected && !_isDisposed) while (client.Connected && !_isDisposed && !token.IsCancellationRequested)
{ {
try try
{ {
@@ -256,7 +261,8 @@ namespace SHH.MjpegPlayer
stopwatch.Stop(); stopwatch.Stop();
var needSleep = frameInterval - (int)stopwatch.ElapsedMilliseconds; var needSleep = frameInterval - (int)stopwatch.ElapsedMilliseconds;
if (needSleep > 0) Thread.Sleep(needSleep); if (needSleep > 0)
Task.Delay(needSleep, token).Wait(token);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -333,6 +339,15 @@ namespace SHH.MjpegPlayer
{ {
if (_isDisposed) return; if (_isDisposed) return;
_isDisposed = true; _isDisposed = true;
// 释放令牌资源
try
{
_sessionCts?.Cancel();
_sessionCts?.Dispose();
}
catch { }
MjpegStatics.Sessions.RemoveSession(this); MjpegStatics.Sessions.RemoveSession(this);
} }