server finish nlog

This commit is contained in:
SikongJueluo 2025-04-10 21:53:21 +08:00
parent 143d6c634b
commit c9660633f0
No known key found for this signature in database
8 changed files with 247 additions and 45 deletions

View File

@ -1,14 +1,16 @@
using System.Reflection; using System.Reflection;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using NLog; using NLog;
using NLog.Web; using NLog.Web;
// Early init of NLog to allow startup and exception logging, before host is built // Early init of NLog to allow startup and exception logging, before host is built
var logger = NLog.LogManager.Setup() var logger = NLog.LogManager.Setup()
.LoadConfigurationFromAppSettings() .LoadConfigurationFromAppSettings()
.GetCurrentClassLogger(); .GetCurrentClassLogger();
logger.Debug("Init Main..."); logger.Debug("Init Main...");
try try
{ {
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -21,6 +23,14 @@ try
builder.Host.UseNLog(); builder.Host.UseNLog();
builder.Services.AddEndpointsApiExplorer(); 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 // Add Swagger
builder.Services.AddSwaggerGen(options => builder.Services.AddSwaggerGen(options =>
{ {
@ -70,10 +80,14 @@ try
MsgBus.Init(); MsgBus.Init();
// Router // Router
// API Get
app.MapGet("/", () => Results.Redirect("/swagger")); app.MapGet("/", () => Results.Redirect("/swagger"));
app.MapGet("/api/GetRecvDataArray", Router.API.GetRecvDataArray);
app.MapPut("/api/SendString", Router.API.SendString); app.MapPut("/api/SendString", Router.API.SendString);
// API Put
app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage); app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage);
app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage); app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage);
// API Jtag Put
app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand); app.MapPut("/api/jtag/RunCommand", Router.API.Jtag.RunCommand);
app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode); app.MapPut("/api/jtag/GetIDCode", Router.API.Jtag.GetDeviceIDCode);
@ -89,9 +103,11 @@ finally
{ {
// Close UDP Server // Close UDP Server
logger.Info("Program is Closing now..."); logger.Info("Program is Closing now...");
MsgBus.Exit();
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux) // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown(); NLog.LogManager.Shutdown();
// Close Program
MsgBus.Exit();
} }

View File

@ -28,6 +28,10 @@
"type": "File", "type": "File",
"fileName": "./log/web-all-${shortdate}.log" "fileName": "./log/web-all-${shortdate}.log"
}, },
"EachFile": {
"type": "File",
"fileName": "./log/${logger}-${shortdate}.log"
},
"Console": { "Console": {
"type": "ColoredConsole" "type": "ColoredConsole"
} }
@ -55,6 +59,16 @@
"logger": "Microsoft.Hosting.Lifetime*", "logger": "Microsoft.Hosting.Lifetime*",
"finalMinLevel": "Info", "finalMinLevel": "Info",
"writeTo": "Console" "writeTo": "Console"
},
{
"logger": "server.*",
"finalMinLevel": "Trace",
"writeTo": "EachFile"
},
{
"logger": "server.*",
"finalMinLevel": "Debug",
"writeTo": "Console"
} }
] ]
} }

View File

@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DotNext" Version="5.19.1" /> <PackageReference Include="DotNext" Version="5.19.1" />
<PackageReference Include="DotNext.Threading" Version="5.19.1" /> <PackageReference Include="DotNext.Threading" Version="5.19.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.4" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.23" /> <PackageReference Include="Microsoft.OpenApi" Version="1.6.23" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.4.0" /> <PackageReference Include="NLog" Version="5.4.0" />

View File

@ -254,10 +254,10 @@ class Jtag
throw new Exception("Get None after Time out!"); throw new Exception("Get None after Time out!");
var recvData = data.Value; 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!"); throw new Exception("Receive Data From Wrong Board!");
var retPack = RecvDataPackage.FromBytes(recvData.data); var retPack = RecvDataPackage.FromBytes(recvData.Data);
if (!retPack.IsSuccessful) if (!retPack.IsSuccessful)
throw new Exception("Not RecvDataPackage!", retPack.Error); throw new Exception("Not RecvDataPackage!", retPack.Error);
@ -304,10 +304,10 @@ class Jtag
throw new Exception("Get None after Time out!"); throw new Exception("Get None after Time out!");
var recvData = data.Value; 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!"); throw new Exception("Receive Data From Wrong Board!");
var retPack = RecvDataPackage.FromBytes(recvData.data); var retPack = RecvDataPackage.FromBytes(recvData.Data);
if (!retPack.IsSuccessful) if (!retPack.IsSuccessful)
throw new Exception("Not RecvDataPackage!", retPack.Error); throw new Exception("Not RecvDataPackage!", retPack.Error);

View File

@ -1,5 +1,3 @@
/// <summary> /// <summary>
/// 多线程通信总线 /// 多线程通信总线
/// </summary> /// </summary>

View File

@ -1,13 +1,33 @@
using System.Net; using System.Net;
using Common; using Common;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace Router namespace Router
{ {
struct Response /// <summary>
/// Custom Web Http Response
/// </summary>
public class Response
{ {
public bool IsSuccess; /// <summary>
public object? Data; /// 是否成功执行
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 数据
/// </summary>
public object? Data { get; set; }
/// <summary>
/// 转换为Json格式的字符串
/// </summary>
/// <returns>Json字符串</returns>
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
} }
/// <summary> /// <summary>
@ -15,6 +35,9 @@ namespace Router
/// </summary> /// </summary>
class API class API
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private const string LOCALHOST = "127.0.0.1";
/// <summary> /// <summary>
/// 发送字符串 /// 发送字符串
/// </summary> /// </summary>
@ -64,8 +87,36 @@ namespace Router
else { return Results.Json(new Response() { IsSuccess = false }); } else { return Results.Json(new Response() { IsSuccess = false }); }
} }
[HttpGet()]
public static async ValueTask<IResult> 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 public class Jtag
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
/// <summary> /// <summary>
/// 执行一个Jtag命令 /// 执行一个Jtag命令
/// </summary> /// </summary>

View File

@ -3,26 +3,36 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using DotNext; using DotNext;
using DotNext.Threading; using DotNext.Threading;
using Newtonsoft.Json;
/// <summary> UDP接受数据包格式 </summary> /// <summary> UDP接受数据包格式 </summary>
public struct UDPData public class UDPData
{ {
/// <summary> /// <summary>
/// 接受到的时间 /// 接受到的时间
/// </summary> /// </summary>
public DateTime datetime; public DateTime DateTime { get; set; }
/// <summary> /// <summary>
/// 发送来源的IP地址 /// 发送来源的IP地址
/// </summary> /// </summary>
public string addr; public string Address { get; set; }
/// <summary> /// <summary>
/// 发送来源的端口号 /// 发送来源的端口号
/// </summary> /// </summary>
public int port; public int Port { get; set; }
/// <summary> /// <summary>
/// 接受到的数据 /// 接受到的数据
/// </summary> /// </summary>
public byte[] data; public byte[] Data { get; set; }
/// <summary>
/// 将UDP Data 转化为Json 格式字符串
/// </summary>
/// <returns>json字符串</returns>
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
} }
/// <summary> /// <summary>
@ -30,6 +40,8 @@ public struct UDPData
/// </summary> /// </summary>
public class UDPServer public class UDPServer
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private int listenPort; private int listenPort;
private UdpClient listener; private UdpClient listener;
private IPEndPoint groupEP; private IPEndPoint groupEP;
@ -142,6 +154,38 @@ public class UDPServer
} }
} }
public async ValueTask<Optional<List<UDPData>>> GetDataArrayAsync(string ipAddr, int timeout = 1000)
{
List<UDPData>? 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<List<UDPData>>();
}
else
{
return Optional.Some((List<UDPData>)data);
}
}
private void ReceiveHandler(IAsyncResult res) private void ReceiveHandler(IAsyncResult res)
{ {
var remoteEP = new IPEndPoint(IPAddress.Any, listenPort); var remoteEP = new IPEndPoint(IPAddress.Any, listenPort);
@ -150,33 +194,42 @@ public class UDPServer
// Handle RemoteEP // Handle RemoteEP
string remoteStr = "Unknown"; string remoteStr = "Unknown";
if (remoteEP is not null) using (udpDataLock.AcquireWriteLock())
{ {
var remoteAddress = remoteEP.Address.ToString(); if (remoteEP is not null)
var remotePort = remoteEP.Port;
// Record UDP Receive Data
if (udpData.ContainsKey(remoteAddress))
{ {
var listData = udpData[remoteAddress]; var remoteAddress = remoteEP.Address.ToString();
listData.Add(new UDPData() var remotePort = remoteEP.Port;
// Record UDP Receive Data
if (udpData.ContainsKey(remoteAddress))
{ {
addr = remoteAddress, var listData = udpData[remoteAddress];
port = remotePort, listData.Add(new UDPData()
data = bytes, {
datetime = nowtime, Address = remoteAddress,
}); Port = remotePort,
Data = bytes,
DateTime = nowtime,
});
logger.Trace("Receive data from old client");
}
else
{
udpData.Add(remoteAddress, new List<UDPData>([new UDPData(){
Address = remoteAddress,
Port = remotePort,
Data = bytes,
DateTime = nowtime,
}]));
logger.Trace("Receive data from new client");
}
remoteStr = $"{remoteAddress}:{remotePort}";
} }
else else
{ {
udpData.Add(remoteAddress, new List<UDPData>([new UDPData(){ logger.Warn("Receive data from unknown client");
addr = remoteAddress,
port = remotePort,
data = bytes,
datetime = nowtime,
}]));
} }
remoteStr = $"{remoteAddress}:{remotePort}";
} }
// Handle Package // Handle Package
@ -212,14 +265,35 @@ public class UDPServer
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
} }
Console.WriteLine($"Receive Data from {remoteStr} at {nowtime.ToString()}:"); logger.Debug($"Receive Data from {remoteStr} at {nowtime.ToString()}:");
Console.WriteLine($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}"); logger.Debug($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}");
if (recvData.Length != 0) Console.WriteLine(recvData); if (recvData.Length != 0) logger.Debug(recvData);
Console.WriteLine(); RecordAllData();
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
} }
/// <summary>
/// 将所有数据输出到log中
/// </summary>
/// <returns> void </returns>
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());
}
}
}
}
/// <summary> /// <summary>
/// Start UDP Server /// Start UDP Server
/// </summary> /// </summary>

View File

@ -141,6 +141,12 @@ namespace WebProtocol
this.address = address; this.address = address;
} }
/// <summary>
/// 使用二进制参数构建地址包
/// </summary>
/// <param name="commandType">二进制命令类型</param>
/// <param name="burstLength">突发长度</param>
/// <param name="address">写入或读取的地址</param>
public SendAddrPackage(byte commandType, byte burstLength, UInt32 address) public SendAddrPackage(byte commandType, byte burstLength, UInt32 address)
{ {
this.commandType = commandType; this.commandType = commandType;
@ -182,6 +188,12 @@ namespace WebProtocol
return JsonConvert.SerializeObject(opts); return JsonConvert.SerializeObject(opts);
} }
/// <summary>
/// 根据字节数组构建地址包
/// </summary>
/// <param name="bytes">字节数组</param>
/// <param name="checkSign">是否校验地址包包头</param>
/// <returns>地址包</returns>
public static Result<SendAddrPackage> FromBytes(byte[] bytes, bool checkSign = true) public static Result<SendAddrPackage> FromBytes(byte[] bytes, bool checkSign = true)
{ {
if (bytes.Length != 8) if (bytes.Length != 8)
@ -205,17 +217,28 @@ namespace WebProtocol
} }
} }
/// <summary> 数据包 </summary>
public struct SendDataPackage public struct SendDataPackage
{ {
readonly byte sign = (byte)PackSign.SendData; readonly byte sign = (byte)PackSign.SendData;
readonly byte[] _reserved = new byte[3]; readonly byte[] _reserved = new byte[3];
readonly byte[] bodyData; readonly byte[] bodyData;
/// <summary>
/// 根据数据内容构建数据包
/// </summary>
/// <param name="bodyData">数据</param>
public SendDataPackage(byte[] bodyData) public SendDataPackage(byte[] bodyData)
{ {
this.bodyData = bodyData; this.bodyData = bodyData;
_ = _reserved;
} }
/// <summary>
/// 将数据包转化为字节数组
/// </summary>
/// <returns>字节数组</returns>
public byte[] ToBytes() public byte[] ToBytes()
{ {
var bodyDataLen = bodyData.Length; var bodyDataLen = bodyData.Length;
@ -231,7 +254,7 @@ namespace WebProtocol
} }
/// <summary> FPGA->Server 读数据包 </summary> /// <summary> FPGA->Server 读响应包 </summary>
public struct RecvDataPackage public struct RecvDataPackage
{ {
readonly byte sign = (byte)PackSign.RecvData; readonly byte sign = (byte)PackSign.RecvData;
@ -241,21 +264,24 @@ namespace WebProtocol
readonly byte[] bodyData; readonly byte[] bodyData;
/// <summary> /// <summary>
/// FPGA->Server 读数据 /// FPGA->Server 读响应
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
/// <param name="commandID"> 任务ID号 </param> /// <param name="commandID"> 任务ID号 </param>
/// <param name="resp"> 读数据包响应 </param> /// <param name="resp"> 读响应包响应 </param>
/// <param name="bodyData"> 数据 </param> /// <param name="bodyData"> 数据 </param>
public RecvDataPackage(byte commandID, byte resp, byte[] bodyData) public RecvDataPackage(byte commandID, byte resp, byte[] bodyData)
{ {
this.commandID = commandID; this.commandID = commandID;
this.resp = resp; this.resp = resp;
this.bodyData = bodyData; this.bodyData = bodyData;
_ = this.sign;
_ = this._reserved;
} }
/// <summary> /// <summary>
/// 获取读数据包选项 /// 获取读响应包选项
/// </summary> /// </summary>
public RecvPackOptions Options public RecvPackOptions Options
{ {
@ -271,6 +297,11 @@ namespace WebProtocol
} }
} }
/// <summary>
/// 从字节数组构建读响应包
/// </summary>
/// <param name="bytes">字节数组</param>
/// <returns>读响应包</returns>
public static Result<RecvDataPackage> FromBytes(byte[] bytes) public static Result<RecvDataPackage> FromBytes(byte[] bytes)
{ {
if (bytes[0] != (byte)PackSign.RecvData) if (bytes[0] != (byte)PackSign.RecvData)
@ -282,6 +313,7 @@ namespace WebProtocol
} }
} }
/// <summary> 写响应包 </summary>
public struct RecvRespPackage public struct RecvRespPackage
{ {
readonly byte sign = (byte)PackSign.RecvResp; readonly byte sign = (byte)PackSign.RecvResp;
@ -289,12 +321,23 @@ namespace WebProtocol
readonly byte resp; readonly byte resp;
readonly byte _reserved = 0; readonly byte _reserved = 0;
/// <summary>
/// 构建写响应包
/// </summary>
/// <param name="commandID">任务ID</param>
/// <param name="resp">写响应</param>
public RecvRespPackage(byte commandID, byte resp) public RecvRespPackage(byte commandID, byte resp)
{ {
this.commandID = commandID; this.commandID = commandID;
this.resp = resp; this.resp = resp;
_ = this.sign;
_ = this._reserved;
} }
/// <summary>
/// 获取写响应包选项
/// </summary>
public RecvPackOptions Options public RecvPackOptions Options
{ {
get get
@ -309,6 +352,11 @@ namespace WebProtocol
} }
} }
/// <summary>
/// 从字节数组构建写响应包
/// </summary>
/// <param name="bytes">字节数组</param>
/// <returns>写响应包</returns>
public static Result<RecvRespPackage> FromBytes(byte[] bytes) public static Result<RecvRespPackage> FromBytes(byte[] bytes)
{ {
if (bytes[0] != (byte)PackSign.RecvResp) if (bytes[0] != (byte)PackSign.RecvResp)