rewrite udp server handler, change router and protocol

This commit is contained in:
SikongJueluo 2025-04-14 21:31:50 +08:00
parent 5fa4860bfb
commit ae34cf6436
No known key found for this signature in database
5 changed files with 289 additions and 78 deletions

View File

@ -79,13 +79,16 @@ try
// Setup Program // Setup Program
MsgBus.Init(); MsgBus.Init();
// if (app.Environment.IsDevelopment()) MsgBus.UDPServer.EnableDebugMode = true;
MsgBus.UDPServer.EnableDebugMode = true;
// Router // Router
// API Get // API Get
app.MapGet("/", () => Results.Redirect("/swagger")); app.MapGet("/", () => Results.Redirect("/swagger"));
app.MapGet("/api/GetRecvDataArray", Router.API.GetRecvDataArray); app.MapGet("/api/GetRecvDataArray", Router.API.GetRecvDataArray);
// API Post
app.MapPost("/api/SendString", Router.API.SendString); app.MapPost("/api/SendString", Router.API.SendString);
// API Put app.MapPost("/api/SendBytes", Router.API.SendBytes);
app.MapPost("/api/SendAddrPackage", Router.API.SendAddrPackage); app.MapPost("/api/SendAddrPackage", Router.API.SendAddrPackage);
app.MapPost("/api/SendDataPackage", Router.API.SendDataPackage); app.MapPost("/api/SendDataPackage", Router.API.SendDataPackage);
// API Jtag // API Jtag

View File

@ -64,7 +64,7 @@ namespace Common
return num; return num;
} }
public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len) public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
{ {
@ -99,7 +99,7 @@ namespace Common
} }
public static Result<byte[]> StringToBytes(string str, int numBase = 16) public static byte[] StringToBytes(string str, int numBase = 16)
{ {
var len = str.Length; var len = str.Length;
var bytesLen = len / 2; var bytesLen = len / 2;

View File

@ -39,19 +39,41 @@ namespace Router
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private const string LOCALHOST = "127.0.0.1"; private const string LOCALHOST = "127.0.0.1";
/// <summary> /// <summary>
/// 发送字符串 /// 发送字符串
/// </summary> /// </summary>
/// <param name="address">IPV4 或者 IPV6 地址</param> /// <param name="address" example="127.0.0.1">IPV4 或者 IPV6 地址</param>
/// <param name="port">设备端口号</param> /// <param name="port" example="1234">设备端口号</param>
/// <param name="text">Text for send</param> /// <param name="text" example="Hello Server!">Text for send</param>
/// <returns>Json: true or false</returns> [HttpPost("{address}/{port}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> SendString(string address, int port, string text) public static async ValueTask<IResult> SendString(string address, int port, string text)
{ {
var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
var ret = await UDPClientPool.SendStringAsync(endPoint, [text]); var ret = await UDPClientPool.SendStringAsync(endPoint, [text]);
if (ret) { return Results.Json(new Response() { IsSuccess = true }); }
else { return Results.Json(new Response() { IsSuccess = false }); } if (ret) { return TypedResults.Ok(); }
else { return TypedResults.InternalServerError(); }
}
/// <summary>
/// 发送二进制数据
/// </summary>
/// <param name="address" example="127.0.0.1">IPV4 或者 IPV6 地址</param>
/// <param name="port" example="1234">设备端口号</param>
/// <param name="bytes" example="FFFFAAAA">16进制文本</param>
[HttpPost("{address}/{port}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> SendBytes(string address, int port, string bytes)
{
var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
var ret = await UDPClientPool.SendBytesAsync(endPoint, NumberProcessor.StringToBytes(bytes));
if (ret) { return TypedResults.Ok(); }
else { return TypedResults.InternalServerError(); }
} }
@ -62,8 +84,8 @@ namespace Router
/// <param name="port" example="1234">UDP 端口号</param> /// <param name="port" example="1234">UDP 端口号</param>
/// <param name="opts">地址包选项</param> /// <param name="opts">地址包选项</param>
[HttpPost("{address}/{port}")] [HttpPost("{address}/{port}")]
[ProducesResponseType(200)] [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(500)] [ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> SendAddrPackage( public static async ValueTask<IResult> SendAddrPackage(
string address, string address,
int port, int port,
@ -71,20 +93,27 @@ namespace Router
{ {
var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
var ret = await UDPClientPool.SendAddrPackAsync(endPoint, new WebProtocol.SendAddrPackage(opts)); var ret = await UDPClientPool.SendAddrPackAsync(endPoint, new WebProtocol.SendAddrPackage(opts));
if (ret) { return TypedResults.Ok(); } if (ret) { return TypedResults.Ok(); }
else { return TypedResults.InternalServerError(); } else { return TypedResults.InternalServerError(); }
} }
[HttpPost("{address}/{port}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> SendDataPackage(string address, int port, string data) public static async ValueTask<IResult> SendDataPackage(string address, int port, string data)
{ {
var endPoint = new IPEndPoint(IPAddress.Parse(address), port); var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
var ret = await UDPClientPool.SendDataPackAsync(endPoint, var ret = await UDPClientPool.SendDataPackAsync(endPoint,
new WebProtocol.SendDataPackage(NumberProcessor.StringToBytes(data).Value)); new WebProtocol.SendDataPackage(NumberProcessor.StringToBytes(data)));
if (ret) { return Results.Json(new Response() { IsSuccess = true }); }
else { return Results.Json(new Response() { IsSuccess = false }); } if (ret) { return TypedResults.Ok(); }
else { return TypedResults.InternalServerError(); }
} }
[HttpGet("{address}")] [HttpGet("{address}")]
[ProducesResponseType(typeof(List<UDPData>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> GetRecvDataArray(string address) public static async ValueTask<IResult> GetRecvDataArray(string address)
{ {
var ret = await MsgBus.UDPServer.GetDataArrayAsync(address); var ret = await MsgBus.UDPServer.GetDataArrayAsync(address);
@ -94,26 +123,19 @@ namespace Router
var dataJson = JsonConvert.SerializeObject(ret.Value); var dataJson = JsonConvert.SerializeObject(ret.Value);
logger.Debug($"Get Receive Successfully: {dataJson}"); logger.Debug($"Get Receive Successfully: {dataJson}");
return TypedResults.Ok(new Response return TypedResults.Ok(ret.Value);
{
IsSuccess = true,
Data = ret.Value,
});
} }
else else
{ {
logger.Debug("Get Receive Failed"); logger.Debug("Get Receive Failed");
return TypedResults.Json(new Response return TypedResults.InternalServerError();
{
IsSuccess = false,
Data = ""
});
} }
} }
public class Jtag public class Jtag
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
/// <summary> /// <summary>
/// 执行一个Jtag命令 /// 执行一个Jtag命令
/// </summary> /// </summary>
@ -121,16 +143,16 @@ namespace Router
/// <param name="port"> 设备端口 </param> /// <param name="port"> 设备端口 </param>
/// <param name="hexDevAddr"> 16进制设备目的地址(Jtag) </param> /// <param name="hexDevAddr"> 16进制设备目的地址(Jtag) </param>
/// <param name="hexCmd"> 16进制命令 </param> /// <param name="hexCmd"> 16进制命令 </param>
/// <param name="hexExRet"> 16进制预期结果 </param> [HttpPost]
/// <returns> Response </returns> [ProducesResponseType(StatusCodes.Status200OK)]
public static async ValueTask<IResult> RunCommand(string address, int port, string hexDevAddr, string hexCmd, string hexExRet) [ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> RunCommand(string address, int port, string hexDevAddr, string hexCmd)
{ {
var jtagCtrl = new JtagController.Jtag(address, port); var jtagCtrl = new JtagController.Jtag(address, port);
var ret = await jtagCtrl.RunCommand(Convert.ToUInt32(hexDevAddr, 16), Convert.ToUInt32(hexCmd, 16), Convert.ToUInt32(hexExRet, 16)); var ret = await jtagCtrl.RunCommand(Convert.ToUInt32(hexDevAddr, 16), Convert.ToUInt32(hexCmd, 16));
if (ret.IsSuccessful) { return TypedResults.Ok(ret.Value); }
if (ret.IsSuccessful) { return Results.Json(new Response() { IsSuccess = true }); } else { return TypedResults.InternalServerError(ret.Error); }
else { return Results.Json(new Response() { IsSuccess = false, Data = ret.Error }); }
} }
@ -139,14 +161,16 @@ namespace Router
/// </summary> /// </summary>
/// <param name="address"> 设备地址 </param> /// <param name="address"> 设备地址 </param>
/// <param name="port"> 设备端口 </param> /// <param name="port"> 设备端口 </param>
/// <returns> Response </returns> [HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public static async ValueTask<IResult> GetDeviceIDCode(string address, int port) public static async ValueTask<IResult> GetDeviceIDCode(string address, int port)
{ {
var jtagCtrl = new JtagController.Jtag(address, port); var jtagCtrl = new JtagController.Jtag(address, port);
var ret = await jtagCtrl.ReadIDCode(); var ret = await jtagCtrl.ReadIDCode();
if (ret.IsSuccessful) { return Results.Json(new Response() { IsSuccess = true, Data = ret.Value }); } if (ret.IsSuccessful) { return TypedResults.Ok(ret.Value); }
else { return Results.Json(new Response() { IsSuccess = false, Data = ret.Error }); } else { return TypedResults.InternalServerError(ret.Error); }
} }

View File

@ -1,6 +1,7 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
using DotNext; using DotNext;
using DotNext.Threading; using DotNext.Threading;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -42,6 +43,9 @@ public class UDPData
/// <summary> /// <summary>
/// UDP Server /// UDP Server
/// </summary> /// </summary>
/// <summary>
/// UDP 服务器
/// </summary>
public class UDPServer public class UDPServer
{ {
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
@ -52,6 +56,11 @@ public class UDPServer
private Dictionary<string, List<UDPData>> udpData = new Dictionary<string, List<UDPData>>(); private Dictionary<string, List<UDPData>> udpData = new Dictionary<string, List<UDPData>>();
private AsyncReaderWriterLock udpDataLock = new AsyncReaderWriterLock(1); private AsyncReaderWriterLock udpDataLock = new AsyncReaderWriterLock(1);
/// <summary>
/// 是否开启Debug模式
/// </summary>
public bool EnableDebugMode { get; set; }
/// <summary> /// <summary>
/// Construct a udp server with fixed port /// Construct a udp server with fixed port
/// </summary> /// </summary>
@ -256,52 +265,133 @@ public class UDPServer
{ {
var remoteEP = new IPEndPoint(IPAddress.Any, listenPort); var remoteEP = new IPEndPoint(IPAddress.Any, listenPort);
byte[] bytes = listener.EndReceive(res, ref remoteEP); byte[] bytes = listener.EndReceive(res, ref remoteEP);
var nowtime = DateTime.Now;
// Handle RemoteEP // Handle RemoteEP
string remoteStr = "Unknown"; if (remoteEP is null)
using (udpDataLock.AcquireWriteLock())
{ {
if (remoteEP is not null) logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
{ logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
var remoteAddress = remoteEP.Address.ToString(); goto BEGIN_RECEIVE;
var remotePort = remoteEP.Port; }
// Record UDP Receive Data
if (udpData.ContainsKey(remoteAddress))
{
var listData = udpData[remoteAddress];
listData.Add(new UDPData()
{
Address = remoteAddress,
Port = remotePort,
Data = bytes,
DateTime = nowtime,
HasRead = false,
});
logger.Trace("Receive data from old client");
}
else
{
udpData.Add(remoteAddress, new List<UDPData>([new UDPData()
{
Address = remoteAddress,
Port = remotePort,
Data = bytes,
DateTime = nowtime,
HasRead = false,
}]));
logger.Trace("Receive data from new client");
}
remoteStr = $"{remoteAddress}:{remotePort}";
// If enable Debug mode, exec Debug handler
if (EnableDebugMode)
{
DebugHandler(new IPEndPoint(IPAddress.Parse("127.0.0.1"), this.listenPort), bytes);
}
else
{
// Handle Package
PrintData(RecordUDPData(bytes, remoteEP));
}
BEGIN_RECEIVE:
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
}
private void DebugHandler(IPEndPoint ep, byte[] bytes)
{
// Print Receive Data
var data = new UDPData()
{
Address = ep.Address.ToString(),
Port = ep.Port,
Data = bytes,
DateTime = DateTime.Now,
HasRead = false,
};
PrintData(data);
// Handle Pack Type
var sign = bytes[0];
if (sign == (byte)WebProtocol.PackSign.SendAddr)
{
var resData = WebProtocol.SendAddrPackage.FromBytes(bytes);
if (!resData.IsSuccessful)
{
logger.Warn("DebugHandler: Convert to SendAddrPackage failed");
return;
}
if (resData.Value.Options.IsWrite)
{
var pack = new WebProtocol.RecvRespPackage(resData.Value.Options.CommandID, true);
SendBytes(ep, pack.ToBytes());
} }
else else
{ {
logger.Warn("Receive data from unknown client"); var pack = new WebProtocol.RecvDataPackage(resData.Value.Options.CommandID, true, [0, 0, 0, 0]);
SendBytes(ep, pack.ToBytes());
} }
} }
else if (sign == (byte)WebProtocol.PackSign.SendData)
{
}
else
{
SendString(ep, "DebugHandler: Receive Data");
}
// Handle Package logger.Trace("DebugHandler: send pack successfully");
}
private bool SendBytes(IPEndPoint endPoint, byte[] buf)
{
var sendLen = listener.Send(buf, endPoint);
if (sendLen == buf.Length) { return true; }
else { return false; }
}
private bool SendString(IPEndPoint endPoint, string text)
{
byte[] buf = Encoding.ASCII.GetBytes(text);
var sendLen = listener.Send(buf, endPoint);
if (sendLen == buf.Length) { return true; }
else { return false; }
}
private UDPData RecordUDPData(byte[] bytes, IPEndPoint remoteEP)
{
using (udpDataLock.AcquireWriteLock())
{
var remoteAddress = remoteEP.Address.ToString();
var remotePort = remoteEP.Port;
var data = new UDPData()
{
Address = remoteAddress,
Port = remotePort,
Data = bytes,
DateTime = DateTime.Now,
HasRead = false,
};
// Record UDP Receive Data
if (udpData.ContainsKey(remoteAddress))
{
var listData = udpData[remoteAddress];
listData.Add(data);
logger.Trace("Receive data from old client");
}
else
{
udpData.Add(remoteAddress, new List<UDPData>([data]));
logger.Trace("Receive data from new client");
}
return data;
}
}
/// <summary>
/// 输出UDP Data到log中
/// </summary>
/// <param name="data">UDP数据</param>
public void PrintData(UDPData data)
{
var bytes = data.Data;
var sign = bytes[0]; var sign = bytes[0];
string recvData = ""; string recvData = "";
if (sign == (byte)WebProtocol.PackSign.SendAddr) if (sign == (byte)WebProtocol.PackSign.SendAddr)
@ -334,20 +424,16 @@ public class UDPServer
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
} }
logger.Debug($"Receive Data from {remoteStr} at {nowtime.ToString()}:"); logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:");
logger.Debug($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}"); logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
if (recvData.Length != 0) logger.Debug(recvData); if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}");
// RecordAllData();
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
} }
/// <summary> /// <summary>
/// 将所有数据输出到log中 /// 将所有数据输出到log中
/// </summary> /// </summary>
/// <returns> void </returns> /// <returns> void </returns>
public void RecordAllData() public void PrintAllData()
{ {
using (udpDataLock.AcquireReadLock()) using (udpDataLock.AcquireReadLock())
{ {

View File

@ -172,6 +172,24 @@ namespace WebProtocol
this.address = address; this.address = address;
} }
/// <summary>
/// 获取对应地址包选项
/// </summary>
public SendAddrPackOptions Options
{
get
{
return new SendAddrPackOptions()
{
Address = this.address,
BurstLength = this.burstLength,
BurstType = (BurstType)(this.commandType >> 6),
CommandID = Convert.ToByte((this.commandType >> 4) & 0b11),
IsWrite = Convert.ToBoolean(this.commandType & 1)
};
}
}
/// <summary> /// <summary>
/// 将地址包转化为字节数组 /// 将地址包转化为字节数组
/// </summary> /// </summary>
@ -298,6 +316,31 @@ namespace WebProtocol
_ = this._reserved; _ = this._reserved;
} }
/// <summary>
/// FPGA->Server 读响应包
/// 构造函数
/// </summary>
/// <param name="commandID"> 任务ID号 </param>
/// <param name="isSuccess">是否读取成功</param>
/// <param name="bodyData"> 数据 </param>
public RecvDataPackage(byte commandID, bool isSuccess, byte[] bodyData)
{
this.commandID = commandID;
this.resp = Convert.ToByte(isSuccess);
this.bodyData = bodyData;
}
/// <summary>
/// 通过接受包选项构建读响应包
/// </summary>
/// <param name="opts">接收包(读响应包和写响应包)选项</param>
public RecvDataPackage(RecvPackOptions opts)
{
this.commandID = opts.CommandID;
this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00);
this.bodyData = opts.Data ?? (byte[])[0, 0, 0, 0];
}
/// <summary> /// <summary>
/// 获取读响应包选项 /// 获取读响应包选项
/// </summary> /// </summary>
@ -337,6 +380,25 @@ namespace WebProtocol
); );
return new RecvDataPackage(bytes[1], bytes[2], bytes[4..]); return new RecvDataPackage(bytes[1], bytes[2], bytes[4..]);
} }
/// <summary>
/// 将数据包转化为字节数组
/// </summary>
/// <returns>字节数组</returns>
public byte[] ToBytes()
{
var bodyDataLen = bodyData.Length;
var arr = new byte[4 + bodyDataLen];
arr[0] = this.sign;
arr[1] = this.commandID;
arr[2] = this.resp;
Array.Copy(bodyData, 0, arr, 4, bodyDataLen);
return arr;
}
} }
/// <summary> 写响应包 </summary> /// <summary> 写响应包 </summary>
@ -361,6 +423,27 @@ namespace WebProtocol
_ = this._reserved; _ = this._reserved;
} }
/// <summary>
/// 构建写响应包
/// </summary>
/// <param name="commandID">任务ID</param>
/// <param name="isSuccess">是否写成功</param>
public RecvRespPackage(byte commandID, bool isSuccess)
{
this.commandID = commandID;
this.resp = Convert.ToByte(isSuccess);
}
/// <summary>
/// 通过接受包选项构建写响应包
/// </summary>
/// <param name="opts">接收包(读响应包和写响应包)选项</param>
public RecvRespPackage(RecvPackOptions opts)
{
this.commandID = opts.CommandID;
this.resp = Convert.ToByte(opts.IsSuccess ? 0b10 : 0b00);
}
/// <summary> /// <summary>
/// 获取写响应包选项 /// 获取写响应包选项
/// </summary> /// </summary>
@ -400,5 +483,20 @@ namespace WebProtocol
); );
return new RecvRespPackage(bytes[1], bytes[2]); return new RecvRespPackage(bytes[1], bytes[2]);
} }
/// <summary>
/// 将数据包转化为字节数组
/// </summary>
/// <returns>字节数组</returns>
public byte[] ToBytes()
{
var arr = new byte[4];
arr[0] = this.sign;
arr[1] = this.commandID;
arr[2] = this.resp;
return arr;
}
} }
} }