finish web test api

This commit is contained in:
SikongJueluo 2025-03-31 20:24:26 +08:00
parent f455af3589
commit 0da5b85173
No known key found for this signature in database
10 changed files with 392 additions and 59 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
root = true
# Default
[*]
indent_style = space
indent_size = 2
tab_width = 2
[*.cs]
indent_style = space
indent_size = 4
tab_width = 4

View File

@ -27,6 +27,7 @@
])
nuget
omnisharp-roslyn
csharpier
# LSP
typescript-language-server

View File

@ -1,3 +1,4 @@
using System.Net;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
@ -22,22 +23,19 @@ if (app.Environment.IsDevelopment())
});
}
// Setup UDP Server
var udpServer = new UDPServer(33000);
udpServer.Start();
// Router
app.MapGet("/", () => "Hello World!");
app.MapPut("/api/SendString", Router.API.SendString);
app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage);
app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage);
var thrdStartUdpServer = new ThreadStart(UDPServer.Start);
var thrdUdpServer = new Thread(thrdStartUdpServer);
thrdUdpServer.Start();
Console.WriteLine("Start UDP Server");
var thrdStartUdpClient = new ThreadStart(UDPClient.Start);
var thrdUdpClient = new Thread(thrdStartUdpClient);
thrdUdpClient.Start();
Console.WriteLine("Start UDP Client");
thrdUdpServer.Join();
thrdUdpClient.Join();
// app.Run("http://localhost:5000");
app.Run("http://localhost:5000");
// Close UDP Server
Console.WriteLine("UDP Server is Closing now...");
udpServer.Stop();

View File

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNext" Version="5.19.1" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.23" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" />

83
server/src/Common.cs Normal file
View File

@ -0,0 +1,83 @@
using DotNext;
namespace Common
{
class NumberProcessor
{
public static Result<byte[]> NumberToBytes(ulong num, uint length, bool isRightHigh = false)
{
if (length > 8)
{
throw new ArgumentException(
"Unsigned long number can't over 8 bytes(64 bits).",
nameof(length)
);
}
var arr = new byte[length];
if (isRightHigh)
{
for (var i = 0; i < length; i++)
{
arr[length - 1 - i] = Convert.ToByte((num >> (i << 3)) & (0xFF));
}
}
else
{
for (var i = 0; i < length; i++)
{
arr[i] = Convert.ToByte((num >> (i << 3)) & (0xFF));
}
}
return arr;
}
public static Result<ulong> BytesToNumber(byte[] bytes, bool isRightLeft = false)
{
if (bytes.Length > 8)
{
throw new ArgumentException(
"Unsigned long number can't over 8 bytes(64 bits).",
nameof(bytes)
);
}
ulong num = 0;
int len = bytes.Length;
if (isRightLeft)
{
for (var i = 0; i < len; i++)
{
num += Convert.ToUInt64(bytes[len - 1 - i] << (i << 3));
}
}
else
{
for (var i = 0; i < len; i++)
{
num += Convert.ToUInt64(bytes[i] << (i << 3));
}
}
return num;
}
public static Result<byte[]> StringToBytes(string str, int numBase = 16)
{
var len = str.Length;
var bytesLen = len / 2;
var bytes = new byte[bytesLen];
for (var i = 0; i < bytesLen; i++)
{
bytes[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
}
return bytes;
}
}
}

41
server/src/Router.cs Normal file
View File

@ -0,0 +1,41 @@
using System.Net;
using Common;
namespace Router
{
class API
{
public static void SendString(string address, int port, string text)
{
var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
UDPClientPool.AsyncSendString(endPoint, [text]);
}
public static void SendAddrPackage(
string address,
int port,
WebProtocol.BurstType burstType,
byte commandID,
bool isWrite,
byte burstLength,
UInt32 devAddress)
{
WebProtocol.SendAddrPackOptions opts;
opts.burstType = burstType;
opts.commandID = commandID;
opts.isWrite = isWrite;
opts.burstLength = burstLength;
opts.address = devAddress;
var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
UDPClientPool.SendAddrPack(endPoint, new WebProtocol.SendAddrPackage(opts));
}
public static void SendDataPackage(string address, int port, string data)
{
var endPoint = new IPEndPoint(IPAddress.Parse(address), port);
UDPClientPool.SendDataPack(endPoint,
new WebProtocol.SendDataPackage(NumberProcessor.StringToBytes(data).Value));
}
}
}

View File

@ -31,6 +31,28 @@ class UDPClientPool
await Task.Run(() => { SendBytes(endPoint, buf); });
}
public static void SendAddrPack(IPEndPoint endPoint, WebProtocol.SendAddrPackage pkg)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SendTo(pkg.ToBytes(), endPoint);
}
public async static void AsyncSendAddrPack(IPEndPoint endPoint, WebProtocol.SendAddrPackage pkg)
{
await Task.Run(() => { SendAddrPack(endPoint, pkg); });
}
public static void SendDataPack(IPEndPoint endPoint, WebProtocol.SendDataPackage pkg)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SendTo(pkg.ToBytes(), endPoint);
}
public async static void AsyncSendDataPack(IPEndPoint endPoint, WebProtocol.SendDataPackage pkg)
{
await Task.Run(() => { SendDataPack(endPoint, pkg); });
}
public static void SendLocalHost(int port, string[] stringArray)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

View File

@ -7,57 +7,87 @@ public class UDPServer
private int listenPort;
private UdpClient listener;
private IPEndPoint groupEP;
private Thread thrd;
private bool isRunning;
public UDPServer(int port)
{
// Construction
listenPort = port;
listener = new UdpClient(listenPort);
groupEP = new IPEndPoint(IPAddress.Any, listenPort);
// New Thread
var thrdStart = new ThreadStart(ReceiveHandler);
thrd = new Thread(thrdStart);
}
private void ReceiveHandler()
{
try
{
while (isRunning)
{
byte[] bytes = listener.Receive(ref groupEP);
listener = new UdpClient(listenPort);
groupEP = new IPEndPoint(IPAddress.Any, listenPort);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw new ArgumentException(
$"Not currect port num: {port}",
nameof(port)
);
}
}
Console.WriteLine($"Received broadcast from {groupEP} :");
Console.WriteLine($" {Encoding.ASCII.GetString(bytes, 0, bytes.Length)}");
}
}
catch (SocketException e)
private void ReceiveHandler(IAsyncResult res)
{
var remoteEP = new IPEndPoint(IPAddress.Any, listenPort);
byte[] bytes = listener.EndReceive(res, ref remoteEP);
var sign = bytes[0];
string recvData;
if (sign == (byte)WebProtocol.PackSign.SendAddr)
{
Console.WriteLine(e);
var resData = WebProtocol.SendAddrPackage.FromBytes(bytes);
if (resData.IsSuccessful)
recvData = resData.Value.ToString();
else
recvData = resData.Error.ToString();
}
finally
else if (sign == (byte)WebProtocol.PackSign.SendData)
{
listener.Close();
recvData = "";
}
else if (sign == (byte)WebProtocol.PackSign.RecvData)
{
recvData = "";
}
else if (sign == (byte)WebProtocol.PackSign.RecvResp)
{
recvData = "";
}
else
{
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
}
string remoteStr = (remoteEP is null) ? "Unknown" : $"{remoteEP.Address.ToString()}:{remoteEP.Port.ToString()}";
Console.WriteLine($"Receive Data from {remoteStr} at {DateTime.Now.ToString()}:");
Console.WriteLine($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}");
if (recvData.Length != 0) Console.WriteLine(recvData);
Console.WriteLine();
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
}
public void Start()
{
isRunning = true;
thrd.Start();
try
{
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
}
}
public void Stop()
{
isRunning = false;
thrd.Join();
listener.Close();
}
}

View File

@ -1,6 +1,8 @@
using DotNext;
using Newtonsoft.Json;
namespace WebProtocol
{
public enum PackSign
{
SendAddr = 0x00,
@ -15,36 +17,179 @@ namespace WebProtocol
FixedBurst = 0b01,
}
public struct SendAddrPackOptions
{
public BurstType burstType;
public byte commandID;
public bool isWrite;
public byte burstLength;
public UInt32 address;
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
public struct RecvPackOptions
{
public byte commandID;
public bool isSuccess;
}
public struct SendAddrPackage
{
readonly byte Sign = (byte)PackSign.SendAddr;
readonly byte sign = (byte)PackSign.SendAddr;
readonly byte commandType;
readonly byte burstLength;
readonly byte _reserved;
readonly byte _reserved = 0;
readonly UInt32 address;
public SendAddrPackage(SendAddrPackOptions opts)
{
byte byteBurstType = Convert.ToByte((byte)opts.burstType << 5);
byte byteCommandID = Convert.ToByte((opts.commandID & 0x03) << 3);
byte byteIsWrite = (opts.isWrite ? (byte)0x01 : (byte)0x00);
this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite);
this.burstLength = opts.burstLength;
this.address = opts.address;
}
public SendAddrPackage(BurstType burstType, byte commandID, bool isWrite)
{
commandType = (
((byte)burstType << 5) |
((commandID & (byte)0x03) << 3) |
(isWrite ? (byte)0x01 : (byte)0x00)
);
byte byteBurstType = Convert.ToByte((byte)burstType << 5);
byte byteCommandID = Convert.ToByte((commandID & 0x03) << 3);
byte byteIsWrite = (isWrite ? (byte)0x01 : (byte)0x00);
this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite);
}
public void toBytes()
public SendAddrPackage(byte commandType, byte burstLength, UInt32 address)
{
this.commandType = commandType;
this.burstLength = burstLength;
this.address = address;
}
public byte[] ToBytes()
{
var arr = new byte[8];
arr[0] = sign;
arr[1] = commandType;
arr[2] = burstLength;
arr[3] = _reserved;
var bytesAddr = Common.NumberProcessor.NumberToBytes(address, 4).Value;
Array.Copy(bytesAddr, 0, arr, 4, bytesAddr.Length);
return arr;
}
public override string ToString()
{
SendAddrPackOptions opts;
opts.burstType = (BurstType)(commandType >> 5);
opts.commandID = Convert.ToByte((commandType >> 3) & 0b0011);
opts.isWrite = Convert.ToBoolean(commandType & 0x01);
opts.burstLength = burstLength;
opts.address = address;
return JsonConvert.SerializeObject(opts);
}
public static Result<SendAddrPackage> FromBytes(byte[] bytes, bool checkSign = true)
{
if (bytes.Length != 8)
{
throw new ArgumentException(
"Bytes are not equal to 8 bytes.",
nameof(bytes)
);
}
if (checkSign && bytes[0] != (byte)PackSign.SendAddr)
{
throw new ArgumentException(
"The sign of bytes is not SendAddr Package, but you can disable it by set checkSign false.",
nameof(bytes)
);
}
var address = Common.NumberProcessor.BytesToNumber(bytes[4..]).Value;
return new SendAddrPackage(bytes[1], bytes[2], Convert.ToUInt32(address));
}
}
public struct RecvRackage
public struct SendDataPackage
{
readonly byte sign = (byte)PackSign.SendData;
readonly byte[] _reserved = new byte[3];
readonly byte[] bodyData;
public void toBytes()
public SendDataPackage(byte[] bodyData)
{
this.bodyData = bodyData;
}
public byte[] ToBytes()
{
var bodyDataLen = bodyData.Length;
var arr = new byte[4 + bodyDataLen];
arr[0] = sign;
Array.Copy(bodyData, 0, arr, 4, bodyDataLen);
return arr;
}
}
public struct RecvDataPackage
{
readonly byte sign = (byte)PackSign.RecvData;
readonly byte commandID;
readonly byte resp;
readonly byte _reserved = 0;
readonly byte[] bodyData;
public RecvDataPackage(byte commandID, byte resp, byte[] bodyData)
{
this.commandID = commandID;
this.resp = resp;
this.bodyData = bodyData;
}
public RecvPackOptions Options()
{
RecvPackOptions opts;
opts.commandID = commandID;
opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
return opts;
}
}
public struct RecvRespPackage
{
readonly byte sign = (byte)PackSign.RecvResp;
readonly byte commandID;
readonly byte resp;
readonly byte _reserved = 0;
public RecvRespPackage(byte commandID, byte resp)
{
this.commandID = commandID;
this.resp = resp;
}
public RecvPackOptions Options()
{
RecvPackOptions opts;
opts.commandID = commandID;
opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
return opts;
}
}
}

View File

@ -23,9 +23,8 @@
</div>
</template>
<script setup lang="ts">
</script>
<script setup lang="ts"></script>
<style scoped>
@import "@/assets/main.css"
@import "@/assets/main.css";
</style>