优化 Mjpeg 播放
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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,9 +339,18 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user