From c9660633f00a8920bc7346a1e4d891aab7e7aa2e Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Thu, 10 Apr 2025 21:53:21 +0800 Subject: [PATCH] server finish nlog --- server/Program.cs | 22 +++++- server/appsettings.json | 14 ++++ server/server.csproj | 1 + server/src/JtagController.cs | 8 +-- server/src/MsgBus.cs | 2 - server/src/Router.cs | 57 ++++++++++++++- server/src/UdpServer.cs | 132 +++++++++++++++++++++++++++-------- server/src/WebProtocol.cs | 56 +++++++++++++-- 8 files changed, 247 insertions(+), 45 deletions(-) diff --git a/server/Program.cs b/server/Program.cs index 6e55bbc..fa389c5 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -1,14 +1,16 @@ using System.Reflection; using Microsoft.OpenApi.Models; +using Newtonsoft.Json; using NLog; using NLog.Web; // Early init of NLog to allow startup and exception logging, before host is built var logger = NLog.LogManager.Setup() - .LoadConfigurationFromAppSettings() - .GetCurrentClassLogger(); + .LoadConfigurationFromAppSettings() + .GetCurrentClassLogger(); logger.Debug("Init Main..."); + try { var builder = WebApplication.CreateBuilder(args); @@ -21,6 +23,14 @@ try builder.Host.UseNLog(); builder.Services.AddEndpointsApiExplorer(); + // Add Json.Net Serializer + builder.Services.AddControllersWithViews().AddNewtonsoftJson(options => + { + // Configure Newtonsoft.Json options here + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + }); + // Add Swagger builder.Services.AddSwaggerGen(options => { @@ -70,10 +80,14 @@ try MsgBus.Init(); // Router + // API Get app.MapGet("/", () => Results.Redirect("/swagger")); + app.MapGet("/api/GetRecvDataArray", Router.API.GetRecvDataArray); app.MapPut("/api/SendString", Router.API.SendString); + // API Put app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage); app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage); + // API Jtag Put app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand); app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode); @@ -89,9 +103,11 @@ finally { // Close UDP Server logger.Info("Program is Closing now..."); - MsgBus.Exit(); // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux) NLog.LogManager.Shutdown(); + + // Close Program + MsgBus.Exit(); } diff --git a/server/appsettings.json b/server/appsettings.json index b2362cc..d035e31 100644 --- a/server/appsettings.json +++ b/server/appsettings.json @@ -28,6 +28,10 @@ "type": "File", "fileName": "./log/web-all-${shortdate}.log" }, + "EachFile": { + "type": "File", + "fileName": "./log/${logger}-${shortdate}.log" + }, "Console": { "type": "ColoredConsole" } @@ -55,6 +59,16 @@ "logger": "Microsoft.Hosting.Lifetime*", "finalMinLevel": "Info", "writeTo": "Console" + }, + { + "logger": "server.*", + "finalMinLevel": "Trace", + "writeTo": "EachFile" + }, + { + "logger": "server.*", + "finalMinLevel": "Debug", + "writeTo": "Console" } ] } diff --git a/server/server.csproj b/server/server.csproj index 114fcae..a903e41 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -13,6 +13,7 @@ + diff --git a/server/src/JtagController.cs b/server/src/JtagController.cs index 269f7bb..a206576 100644 --- a/server/src/JtagController.cs +++ b/server/src/JtagController.cs @@ -254,10 +254,10 @@ class Jtag throw new Exception("Get None after Time out!"); var recvData = data.Value; - if (recvData.addr != address || recvData.port != port) + if (recvData.Address != address || recvData.Port != port) throw new Exception("Receive Data From Wrong Board!"); - var retPack = RecvDataPackage.FromBytes(recvData.data); + var retPack = RecvDataPackage.FromBytes(recvData.Data); if (!retPack.IsSuccessful) throw new Exception("Not RecvDataPackage!", retPack.Error); @@ -304,10 +304,10 @@ class Jtag throw new Exception("Get None after Time out!"); var recvData = data.Value; - if (recvData.addr != address || recvData.port != port) + if (recvData.Address != address || recvData.Port != port) throw new Exception("Receive Data From Wrong Board!"); - var retPack = RecvDataPackage.FromBytes(recvData.data); + var retPack = RecvDataPackage.FromBytes(recvData.Data); if (!retPack.IsSuccessful) throw new Exception("Not RecvDataPackage!", retPack.Error); diff --git a/server/src/MsgBus.cs b/server/src/MsgBus.cs index 1101792..f087f03 100644 --- a/server/src/MsgBus.cs +++ b/server/src/MsgBus.cs @@ -1,5 +1,3 @@ - - /// /// 多线程通信总线 /// diff --git a/server/src/Router.cs b/server/src/Router.cs index e9e193a..dced8b8 100644 --- a/server/src/Router.cs +++ b/server/src/Router.cs @@ -1,13 +1,33 @@ using System.Net; using Common; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; namespace Router { - struct Response + /// + /// Custom Web Http Response + /// + public class Response { - public bool IsSuccess; - public object? Data; + /// + /// 是否成功执行 + /// + public bool IsSuccess { get; set; } + + /// + /// 数据 + /// + public object? Data { get; set; } + + /// + /// 转换为Json格式的字符串 + /// + /// Json字符串 + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } } /// @@ -15,6 +35,9 @@ namespace Router /// class API { + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + private const string LOCALHOST = "127.0.0.1"; /// /// 发送字符串 /// @@ -64,8 +87,36 @@ namespace Router else { return Results.Json(new Response() { IsSuccess = false }); } } + [HttpGet()] + public static async ValueTask GetRecvDataArray(string address) + { + var ret = await MsgBus.UDPServer.GetDataArrayAsync(address); + + if (ret.HasValue) + { + var dataJson = JsonConvert.SerializeObject(ret.Value); + logger.Debug($"Get Receive Successfully: {dataJson}"); + + return TypedResults.Ok(new Response + { + IsSuccess = true, + Data = ret.Value, + }); + } + else + { + logger.Debug("Get Receive Failed"); + return TypedResults.Json(new Response + { + IsSuccess = false, + Data = "" + }); + } + } + public class Jtag { + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); /// /// 执行一个Jtag命令 /// diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs index 546c5e7..c050fb1 100644 --- a/server/src/UdpServer.cs +++ b/server/src/UdpServer.cs @@ -3,26 +3,36 @@ using System.Net.Sockets; using System.Text; using DotNext; using DotNext.Threading; +using Newtonsoft.Json; /// UDP接受数据包格式 -public struct UDPData +public class UDPData { /// /// 接受到的时间 /// - public DateTime datetime; + public DateTime DateTime { get; set; } /// /// 发送来源的IP地址 /// - public string addr; + public string Address { get; set; } /// /// 发送来源的端口号 /// - public int port; + public int Port { get; set; } /// /// 接受到的数据 /// - public byte[] data; + public byte[] Data { get; set; } + + /// + /// 将UDP Data 转化为Json 格式字符串 + /// + /// json字符串 + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } } /// @@ -30,6 +40,8 @@ public struct UDPData /// public class UDPServer { + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + private int listenPort; private UdpClient listener; private IPEndPoint groupEP; @@ -142,6 +154,38 @@ public class UDPServer } } + public async ValueTask>> GetDataArrayAsync(string ipAddr, int timeout = 1000) + { + List? data = null; + + var startTime = DateTime.Now; + var isTimeout = false; + var timeleft = TimeSpan.FromMilliseconds(timeout); + while (!isTimeout) + { + + using (await udpDataLock.AcquireReadLockAsync(timeleft)) + { + if (udpData.ContainsKey(ipAddr)) + { + data = udpData[ipAddr]; + } + } + + timeleft = DateTime.Now.Subtract(startTime); + isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout); + } + + if (data == null) + { + return Optional.None>(); + } + else + { + return Optional.Some((List)data); + } + } + private void ReceiveHandler(IAsyncResult res) { var remoteEP = new IPEndPoint(IPAddress.Any, listenPort); @@ -150,33 +194,42 @@ public class UDPServer // Handle RemoteEP string remoteStr = "Unknown"; - if (remoteEP is not null) + using (udpDataLock.AcquireWriteLock()) { - var remoteAddress = remoteEP.Address.ToString(); - var remotePort = remoteEP.Port; - // Record UDP Receive Data - if (udpData.ContainsKey(remoteAddress)) + if (remoteEP is not null) { - var listData = udpData[remoteAddress]; - listData.Add(new UDPData() + var remoteAddress = remoteEP.Address.ToString(); + var remotePort = remoteEP.Port; + // Record UDP Receive Data + if (udpData.ContainsKey(remoteAddress)) { - addr = remoteAddress, - port = remotePort, - data = bytes, - datetime = nowtime, - }); + var listData = udpData[remoteAddress]; + listData.Add(new UDPData() + { + Address = remoteAddress, + Port = remotePort, + Data = bytes, + DateTime = nowtime, + }); + logger.Trace("Receive data from old client"); + } + else + { + udpData.Add(remoteAddress, new List([new UDPData(){ + Address = remoteAddress, + Port = remotePort, + Data = bytes, + DateTime = nowtime, + }])); + logger.Trace("Receive data from new client"); + } + + remoteStr = $"{remoteAddress}:{remotePort}"; } else { - udpData.Add(remoteAddress, new List([new UDPData(){ - addr = remoteAddress, - port = remotePort, - data = bytes, - datetime = nowtime, - }])); + logger.Warn("Receive data from unknown client"); } - - remoteStr = $"{remoteAddress}:{remotePort}"; } // Handle Package @@ -212,14 +265,35 @@ public class UDPServer recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); } - Console.WriteLine($"Receive Data from {remoteStr} at {nowtime.ToString()}:"); - Console.WriteLine($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}"); - if (recvData.Length != 0) Console.WriteLine(recvData); - Console.WriteLine(); + logger.Debug($"Receive Data from {remoteStr} at {nowtime.ToString()}:"); + logger.Debug($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}"); + if (recvData.Length != 0) logger.Debug(recvData); + RecordAllData(); + listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); } + /// + /// 将所有数据输出到log中 + /// + /// void + public void RecordAllData() + { + using (udpDataLock.AcquireReadLock()) + { + logger.Debug("Ready Data:"); + + foreach (var ip in udpData) + { + foreach (var data in ip.Value) + { + logger.Debug(data.ToString()); + } + } + } + } + /// /// Start UDP Server /// diff --git a/server/src/WebProtocol.cs b/server/src/WebProtocol.cs index a2cf0d5..b205df7 100644 --- a/server/src/WebProtocol.cs +++ b/server/src/WebProtocol.cs @@ -141,6 +141,12 @@ namespace WebProtocol this.address = address; } + /// + /// 使用二进制参数构建地址包 + /// + /// 二进制命令类型 + /// 突发长度 + /// 写入或读取的地址 public SendAddrPackage(byte commandType, byte burstLength, UInt32 address) { this.commandType = commandType; @@ -182,6 +188,12 @@ namespace WebProtocol return JsonConvert.SerializeObject(opts); } + /// + /// 根据字节数组构建地址包 + /// + /// 字节数组 + /// 是否校验地址包包头 + /// 地址包 public static Result FromBytes(byte[] bytes, bool checkSign = true) { if (bytes.Length != 8) @@ -205,17 +217,28 @@ namespace WebProtocol } } + /// 数据包 public struct SendDataPackage { readonly byte sign = (byte)PackSign.SendData; readonly byte[] _reserved = new byte[3]; readonly byte[] bodyData; + /// + /// 根据数据内容构建数据包 + /// + /// 数据 public SendDataPackage(byte[] bodyData) { this.bodyData = bodyData; + + _ = _reserved; } + /// + /// 将数据包转化为字节数组 + /// + /// 字节数组 public byte[] ToBytes() { var bodyDataLen = bodyData.Length; @@ -231,7 +254,7 @@ namespace WebProtocol } - /// FPGA->Server 读数据包 + /// FPGA->Server 读响应包 public struct RecvDataPackage { readonly byte sign = (byte)PackSign.RecvData; @@ -241,21 +264,24 @@ namespace WebProtocol readonly byte[] bodyData; /// - /// FPGA->Server 读数据包 + /// FPGA->Server 读响应包 /// 构造函数 /// /// 任务ID号 - /// 读数据包响应 + /// 读响应包响应 /// 数据 public RecvDataPackage(byte commandID, byte resp, byte[] bodyData) { this.commandID = commandID; this.resp = resp; this.bodyData = bodyData; + + _ = this.sign; + _ = this._reserved; } /// - /// 获取读数据包选项 + /// 获取读响应包选项 /// public RecvPackOptions Options { @@ -271,6 +297,11 @@ namespace WebProtocol } } + /// + /// 从字节数组构建读响应包 + /// + /// 字节数组 + /// 读响应包 public static Result FromBytes(byte[] bytes) { if (bytes[0] != (byte)PackSign.RecvData) @@ -282,6 +313,7 @@ namespace WebProtocol } } + /// 写响应包 public struct RecvRespPackage { readonly byte sign = (byte)PackSign.RecvResp; @@ -289,12 +321,23 @@ namespace WebProtocol readonly byte resp; readonly byte _reserved = 0; + /// + /// 构建写响应包 + /// + /// 任务ID + /// 写响应 public RecvRespPackage(byte commandID, byte resp) { this.commandID = commandID; this.resp = resp; + + _ = this.sign; + _ = this._reserved; } + /// + /// 获取写响应包选项 + /// public RecvPackOptions Options { get @@ -309,6 +352,11 @@ namespace WebProtocol } } + /// + /// 从字节数组构建写响应包 + /// + /// 字节数组 + /// 写响应包 public static Result FromBytes(byte[] bytes) { if (bytes[0] != (byte)PackSign.RecvResp)