From eda1b7da7b75cba263980278239fc2ca32015266 Mon Sep 17 00:00:00 2001
From: root <295172551@qq.com>
Date: Sun, 22 Jun 2025 05:28:31 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9E=E6=97=B6=E6=97=A5?=
=?UTF-8?q?=E5=BF=97=E6=9F=A5=E7=9C=8B=E5=8A=9F=E8=83=BD=EF=BC=9A1.=20?=
=?UTF-8?q?=E5=9C=A8WebSocketManagerService=E4=B8=AD=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E4=B8=AD=E5=A4=AE=E6=97=A5=E5=BF=97=E7=BC=93=E5=AD=98=E9=98=9F?=
=?UTF-8?q?=E5=88=97=202.=20=E5=88=9B=E5=BB=BASSE=E7=AB=AF=E7=82=B9?=
=?UTF-8?q?=E7=94=A8=E4=BA=8E=E5=AE=9E=E6=97=B6=E6=8E=A8=E9=80=81=E6=97=A5?=
=?UTF-8?q?=E5=BF=97=203.=20=E6=96=B0=E5=A2=9ELogs.cshtml=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2=EF=BC=8C=E6=94=AF=E6=8C=81=E8=99=9A=E6=8B=9F=E6=BB=9A?=
=?UTF-8?q?=E5=8A=A8=E5=92=8C=E5=8F=8C=E6=A0=8F=E5=B8=83=E5=B1=80=204.=20?=
=?UTF-8?q?=E5=9C=A8=E5=AF=BC=E8=88=AA=E6=A0=8F=E6=B7=BB=E5=8A=A0=E5=AE=9E?=
=?UTF-8?q?=E6=97=B6=E6=97=A5=E5=BF=97=E5=85=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
LTEMvcApp/Controllers/HomeController.cs | 8 +
LTEMvcApp/Controllers/WebSocketController.cs | 42 ++-
LTEMvcApp/Services/WebSocketManagerService.cs | 25 ++
LTEMvcApp/Views/Home/ClientMessages.cshtml | 162 ++++++-----
LTEMvcApp/Views/Home/Logs.cshtml | 268 ++++++++++++++++++
LTEMvcApp/Views/Shared/_Layout.cshtml | 8 +-
6 files changed, 440 insertions(+), 73 deletions(-)
create mode 100644 LTEMvcApp/Views/Home/Logs.cshtml
diff --git a/LTEMvcApp/Controllers/HomeController.cs b/LTEMvcApp/Controllers/HomeController.cs
index ab795fb..6a64d53 100644
--- a/LTEMvcApp/Controllers/HomeController.cs
+++ b/LTEMvcApp/Controllers/HomeController.cs
@@ -172,4 +172,12 @@ public class HomeController : Controller
ViewBag.ClientName = clientName;
return View();
}
+
+ ///
+ /// 返回 Logs.cshtml 视图
+ ///
+ public IActionResult Logs()
+ {
+ return View();
+ }
}
diff --git a/LTEMvcApp/Controllers/WebSocketController.cs b/LTEMvcApp/Controllers/WebSocketController.cs
index 0831e64..065bb04 100644
--- a/LTEMvcApp/Controllers/WebSocketController.cs
+++ b/LTEMvcApp/Controllers/WebSocketController.cs
@@ -5,6 +5,7 @@ using Newtonsoft.Json.Linq;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using System.Linq;
+using System.Threading;
namespace LTEMvcApp.Controllers
{
@@ -365,12 +366,51 @@ namespace LTEMvcApp.Controllers
[HttpPost("test-client/stop")]
public ActionResult StopTestClient()
{
+ _logger.LogInformation("API 请求: 停止测试客户端");
var success = _webSocketManager.StopTestClient();
if (success)
- return Ok(new { message = "测试客户端已停止" });
+ return Ok(new { message = "测试客户端停止成功" });
else
return BadRequest("停止测试客户端失败");
}
+
+ ///
+ /// 使用 Server-Sent Events (SSE) 实时推送全局日志
+ ///
+ [HttpGet("logs/stream")]
+ public async Task StreamLogs(CancellationToken cancellationToken)
+ {
+ Response.ContentType = "text/event-stream";
+ Response.Headers.Append("Cache-Control", "no-cache");
+ Response.Headers.Append("Connection", "keep-alive");
+
+ int logIndex = 0;
+
+ // 首先,一次性推送所有已缓存的日志
+ var initialLogs = _webSocketManager.GetLogCache().ToList();
+ if (initialLogs.Any())
+ {
+ await SendSseEvent("history", new { logs = initialLogs });
+ await Response.Body.FlushAsync(cancellationToken);
+ logIndex = initialLogs.Count;
+ }
+
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ var logCache = _webSocketManager.GetLogCache();
+ if (logCache.Count() > logIndex)
+ {
+ var newLogs = logCache.Skip(logIndex).ToList();
+ if (newLogs.Any())
+ {
+ await SendSseEvent("new_logs", new { logs = newLogs });
+ await Response.Body.FlushAsync(cancellationToken);
+ logIndex = logCache.Count();
+ }
+ }
+ await Task.Delay(250, cancellationToken);
+ }
+ }
}
///
diff --git a/LTEMvcApp/Services/WebSocketManagerService.cs b/LTEMvcApp/Services/WebSocketManagerService.cs
index 5dde8fa..a45a1bc 100644
--- a/LTEMvcApp/Services/WebSocketManagerService.cs
+++ b/LTEMvcApp/Services/WebSocketManagerService.cs
@@ -23,6 +23,8 @@ namespace LTEMvcApp.Services
private readonly ILogger _logger;
private readonly IServiceProvider _serviceProvider;
private ClientConfig _testClientConfig;
+ private const int LogCacheSize = 10000; // 服务器最多缓存10000条最新日志
+ private readonly ConcurrentQueue _logCache = new ConcurrentQueue();
#endregion
@@ -438,6 +440,16 @@ namespace LTEMvcApp.Services
return GetClientInstance(_testClientConfig.Name);
}
+ ///
+ /// 获取当前缓存的日志
+ ///
+ public IEnumerable GetLogCache() => _logCache;
+
+ ///
+ /// 获取当前缓存的日志总数
+ ///
+ public int GetLogCacheCount() => _logCache.Count;
+
#endregion
#region 私有方法
@@ -466,6 +478,19 @@ namespace LTEMvcApp.Services
private void OnLogsReceived(string clientName, List logs)
{
_logger.LogInformation($"客户端 {clientName} 收到日志: {logs.Count} 条");
+
+ // 将新日志存入中央缓存
+ foreach (var log in logs)
+ {
+ _logCache.Enqueue(log);
+ }
+
+ // 维持缓存大小
+ while (_logCache.Count > LogCacheSize)
+ {
+ _logCache.TryDequeue(out _);
+ }
+
LogsReceived?.Invoke(this, (clientName, logs));
}
diff --git a/LTEMvcApp/Views/Home/ClientMessages.cshtml b/LTEMvcApp/Views/Home/ClientMessages.cshtml
index 49e1e14..efbfbb5 100644
--- a/LTEMvcApp/Views/Home/ClientMessages.cshtml
+++ b/LTEMvcApp/Views/Home/ClientMessages.cshtml
@@ -26,11 +26,9 @@
0
-
-
@section Scripts {
+
+
+
+
+
+
+
+
-
-
-
-
}
\ No newline at end of file
diff --git a/LTEMvcApp/Views/Home/Logs.cshtml b/LTEMvcApp/Views/Home/Logs.cshtml
new file mode 100644
index 0000000..0fad7ea
--- /dev/null
+++ b/LTEMvcApp/Views/Home/Logs.cshtml
@@ -0,0 +1,268 @@
+@{
+ ViewData["Title"] = "实时日志";
+}
+
+
+
+
+@section Scripts {
+
+
+
+}
\ No newline at end of file
diff --git a/LTEMvcApp/Views/Shared/_Layout.cshtml b/LTEMvcApp/Views/Shared/_Layout.cshtml
index c887031..28300a1 100644
--- a/LTEMvcApp/Views/Shared/_Layout.cshtml
+++ b/LTEMvcApp/Views/Shared/_Layout.cshtml
@@ -21,7 +21,13 @@