优化 Mjpeg 播放
This commit is contained in:
@@ -47,30 +47,26 @@ namespace SHH.MjpegPlayer
|
||||
try
|
||||
{
|
||||
var process = Process.GetProcessById(pid);
|
||||
|
||||
if (process != null)
|
||||
{
|
||||
procName = process.ProcessName;
|
||||
process.Kill();
|
||||
|
||||
_sysLog.Warning("拒绝停止高权限系统进程: {Pid} - {Name}", pid, process.ProcessName);
|
||||
_sysLog.Information("成功通过 PID 杀掉进程 - Pid: {Pid}, Name: {Name}", pid, procName);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 找不到 ID 对应的进程,应该是进异常不会进这里
|
||||
_sysLog.Information("成功杀掉进程 - Pid: {Pid}", pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
_sysLog.Warning("无法获取进程实例 - Pid: {Pid}", pid);
|
||||
return false;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
_sysLog.Warning("杀掉进程失败,Pid: {Pid} 不存在", pid);
|
||||
_sysLog.Warning("杀掉进程失败,Pid: {Pid} 不存在或已提前退出", pid);
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_sysLog.Error(ex, "杀掉进程异常, Pid: {Pid}", pid);
|
||||
_sysLog.Error(ex, "杀掉进程异常, Pid: {Pid}, 进程名: {Name}", pid, procName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,123 +65,112 @@ namespace SHH.MjpegPlayer
|
||||
/// <summary>
|
||||
/// 刷新方法调用次数
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="count"></param>
|
||||
public void Refresh(string methodName, uint count = 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
#region 加入集合
|
||||
#region 秒统计同步
|
||||
|
||||
// 加入集合
|
||||
lock (_second)
|
||||
{
|
||||
// 确保键存在
|
||||
if (!_second.ContainsKey(methodName))
|
||||
_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)
|
||||
{
|
||||
if (!_minute.ContainsKey(methodName))
|
||||
_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)
|
||||
{
|
||||
if (!_hour.ContainsKey(methodName))
|
||||
_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)
|
||||
{
|
||||
if (!All.ContainsKey(methodName))
|
||||
All.Add(methodName, 0);
|
||||
|
||||
All[methodName] += (ulong)count;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
//Logs.LogWarning<SumByTime>(ex.Message);
|
||||
// 可选:利用 Ayay 项目规范记录日志
|
||||
// _sysLog.Warning("统计刷新异常: {Msg}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Bat\**" />
|
||||
<EmbeddedResource Remove="Bat\**" />
|
||||
<None Remove="Bat\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CoreWCF.Http" Version="1.8.0" />
|
||||
<PackageReference Include="CoreWCF.Primitives" Version="1.8.0" />
|
||||
|
||||
@@ -13,16 +13,20 @@ namespace SHH.MjpegPlayer
|
||||
/// </summary>
|
||||
public class MjpegSession : IDisposable
|
||||
{
|
||||
#region Defines
|
||||
|
||||
private static readonly ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core);
|
||||
|
||||
#region Counter
|
||||
private CancellationTokenSource? _sessionCts;
|
||||
|
||||
private SumByTime _sumBySecond = new SumByTime();
|
||||
/// <summary>
|
||||
/// 计数器
|
||||
/// </summary>
|
||||
|
||||
/// <summary>计数器</summary>
|
||||
public SumByTime Counter => _sumBySecond;
|
||||
|
||||
// 引入 Disposed 标志位
|
||||
private volatile bool _isDisposed = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Info
|
||||
@@ -43,9 +47,6 @@ namespace SHH.MjpegPlayer
|
||||
|
||||
#endregion
|
||||
|
||||
// [修复] 引入 Disposed 标志位
|
||||
private volatile bool _isDisposed = false;
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
@@ -150,7 +151,10 @@ namespace SHH.MjpegPlayer
|
||||
// 初始化最近接收时间,避免刚连接就被判定为超时
|
||||
LastRecImgTime = DateTime.Now;
|
||||
|
||||
Task.Run(() => { DoWorkTask(client); });
|
||||
// 绑定全局取消令牌,确保系统停止时能立即强制中断所有会话
|
||||
_sessionCts = new CancellationTokenSource();
|
||||
|
||||
Task.Run(() => { DoWorkTask(client, _sessionCts.Token); }, _sessionCts.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -162,7 +166,7 @@ namespace SHH.MjpegPlayer
|
||||
|
||||
#region DoWorkTask
|
||||
|
||||
private void DoWorkTask(TcpClient client)
|
||||
private void DoWorkTask(TcpClient client, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -174,11 +178,12 @@ namespace SHH.MjpegPlayer
|
||||
#region 等待连接, 处理地址栏参数
|
||||
|
||||
int iLoc = 0;
|
||||
while (!client.Connected)
|
||||
while (!client.Connected && !token.IsCancellationRequested)
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
if (++iLoc > 60) return;
|
||||
}
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
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[] doubleNewLine = Encoding.ASCII.GetBytes("\r\n\r\n");
|
||||
|
||||
while (client.Connected && !_isDisposed)
|
||||
while (client.Connected && !_isDisposed && !token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -256,7 +261,8 @@ namespace SHH.MjpegPlayer
|
||||
|
||||
stopwatch.Stop();
|
||||
var needSleep = frameInterval - (int)stopwatch.ElapsedMilliseconds;
|
||||
if (needSleep > 0) Thread.Sleep(needSleep);
|
||||
if (needSleep > 0)
|
||||
Task.Delay(needSleep, token).Wait(token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -333,9 +339,18 @@ namespace SHH.MjpegPlayer
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
_isDisposed = true;
|
||||
|
||||
// 释放令牌资源
|
||||
try
|
||||
{
|
||||
_sessionCts?.Cancel();
|
||||
_sessionCts?.Dispose();
|
||||
}
|
||||
catch { }
|
||||
|
||||
MjpegStatics.Sessions.RemoveSession(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user