using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using DotNext;
using DotNext.Threading;
using Newtonsoft.Json;
/// UDP接受数据包格式
public class UDPData
{
///
/// 接受到的时间
///
public required DateTime DateTime { get; set; }
///
/// 发送来源的IP地址
///
public required string Address { get; set; }
///
/// 发送来源的端口号
///
public required int Port { get; set; }
///
/// 接受到的数据
///
public required byte[] Data { get; set; }
///
/// 是否被读取过
///
public required bool HasRead { get; set; }
///
/// 深度拷贝对象
///
/// UDPData
public UDPData DeepClone()
{
var cloneData = new byte[this.Data.Length];
Buffer.BlockCopy(this.Data, 0, cloneData, 0, this.Data.Length);
return new UDPData()
{
DateTime = this.DateTime,
Address = new string(this.Address),
Port = this.Port,
Data = cloneData,
HasRead = this.HasRead
};
}
///
/// 将UDP Data 转化为Json 格式字符串
///
/// json字符串
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
///
/// UDP Server
///
///
/// UDP 服务器
///
public class UDPServer
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private int listenPort;
private UdpClient listener;
private IPEndPoint groupEP;
private Dictionary> udpData = new Dictionary>();
private AsyncReaderWriterLock udpDataLock = new AsyncReaderWriterLock(1);
///
/// Construct a udp server with fixed port
///
/// Device UDP Port
/// UDPServer class
public UDPServer(int port)
{
// Construction
listenPort = port;
try
{
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)
);
}
}
///
/// Find UDP Receive Data According to ip address
///
/// IP Address
/// Read and Write Wait for Milliseconds
/// 调用函数名称
/// 调用函数位置
/// UDP Data
public Optional FindData(
string ipAddr, int timeout = 1000,
[CallerMemberName] string callerName = "",
[CallerLineNumber] int callerLineNum = 0)
{
UDPData? data = null;
logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr} UDP Data");
var startTime = DateTime.Now;
var isTimeout = false;
var timeleft = TimeSpan.FromMilliseconds(timeout);
while (!isTimeout)
{
using (udpDataLock.AcquireWriteLock(timeleft))
{
if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
{
data = udpData[ipAddr][0].DeepClone();
udpData[ipAddr].RemoveAt(0);
logger.Debug($"Find UDP Data: {data.ToString()}");
break;
}
}
timeleft = DateTime.Now.Subtract(startTime);
isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout);
}
if (data == null)
{
logger.Trace("Get nothing even after time out");
return Optional.None();
}
else
{
return Optional.Some((UDPData)data);
}
}
///
/// 异步寻找目标发送的内容
///
/// 目标IP地址
/// 超时时间
/// 调用函数名称
/// 调用函数位置
///
/// 异步Optional 数据包:
/// Optional 为空时,表明找不到数据;
/// Optional 存在时,为最先收到的数据
///
public async ValueTask> FindDataAsync(
string ipAddr, int timeout = 1000,
[CallerMemberName] string callerName = "",
[CallerLineNumber] int callerLineNum = 0)
{
UDPData? data = null;
logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr} UDP Data");
var startTime = DateTime.Now;
var isTimeout = false;
var timeleft = TimeSpan.FromMilliseconds(timeout);
while (!isTimeout)
{
using (await udpDataLock.AcquireWriteLockAsync(timeleft))
{
if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
{
data = udpData[ipAddr][0].DeepClone();
udpData[ipAddr].RemoveAt(0);
logger.Debug($"Find UDP Data: {data.ToString()}");
break;
}
}
timeleft = DateTime.Now.Subtract(startTime);
isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout);
}
if (data is null)
{
logger.Trace("Get nothing even after time out");
return Optional.None();
}
else
{
return Optional.Some((UDPData)data);
}
}
///
/// 获取还未被读取的数据列表
///
/// IP地址
/// 超时时间
/// 数据列表
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];
logger.Debug($"Find UDP Data Array: {data.ToString()}");
break;
}
}
timeleft = DateTime.Now.Subtract(startTime);
isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout);
}
if (data is null)
{
logger.Trace("Get nothing even after time out");
return Optional.None>();
}
else
{
return Optional.Some((List)data);
}
}
///
/// 异步等待写响应
///
/// IP地址
/// UDP 端口
/// 超时时间范围
/// 接收响应包
public async ValueTask> WaitForAckAsync
(string address, int port, int timeout = 1000)
{
var data = await FindDataAsync(address, timeout);
if (!data.HasValue)
throw new Exception("Get None even after time out!");
var recvData = data.Value;
if (recvData.Address != address || recvData.Port != port)
throw new Exception("Receive Data From Wrong Board!");
var retPack = WebProtocol.RecvRespPackage.FromBytes(recvData.Data);
if (!retPack.IsSuccessful)
throw new Exception("Not RecvDataPackage!", retPack.Error);
return retPack.Value;
}
///
/// 异步等待数据
///
/// IP地址
/// UDP 端口
/// 超时时间范围
/// 接收数据包
public async ValueTask> WaitForDataAsync
(string address, int port, int timeout = 1000)
{
var data = await FindDataAsync(address, timeout);
if (!data.HasValue)
throw new Exception("Get None even after time out!");
var recvData = data.Value;
if (recvData.Address != address || recvData.Port != port)
throw new Exception("Receive Data From Wrong Board!");
var retPack = WebProtocol.RecvDataPackage.FromBytes(recvData.Data);
if (!retPack.IsSuccessful)
throw new Exception("Not RecvDataPackage!", retPack.Error);
return retPack.Value;
}
private void ReceiveHandler(IAsyncResult res)
{
logger.Trace("Enter handler");
var remoteEP = new IPEndPoint(IPAddress.Any, listenPort);
byte[] bytes = listener.EndReceive(res, ref remoteEP);
// Handle RemoteEP
if (remoteEP is null)
{
logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
goto BEGIN_RECEIVE;
}
// Handle Package
PrintData(RecordUDPData(bytes, remoteEP));
BEGIN_RECEIVE:
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
}
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
{
var list = new List();
list.Add(data);
udpData.Add(remoteAddress, list);
logger.Trace("Receive data from new client");
}
return data;
}
}
///
/// 输出UDP Data到log中
///
/// UDP数据
public void PrintData(UDPData data)
{
var bytes = data.Data;
var sign = bytes[0];
string recvData = "";
if (sign == (byte)WebProtocol.PackSign.SendAddr)
{
var resData = WebProtocol.SendAddrPackage.FromBytes(bytes);
if (resData.IsSuccessful)
recvData = resData.Value.ToString();
else
recvData = resData.Error.ToString();
}
else if (sign == (byte)WebProtocol.PackSign.SendData) { }
else if (sign == (byte)WebProtocol.PackSign.RecvData)
{
var resData = WebProtocol.RecvDataPackage.FromBytes(bytes);
if (resData.IsSuccessful)
recvData = resData.Value.Options.ToString();
else
recvData = resData.Error.ToString();
}
else if (sign == (byte)WebProtocol.PackSign.RecvResp)
{
var resData = WebProtocol.RecvRespPackage.FromBytes(bytes);
if (resData.IsSuccessful)
recvData = resData.Value.Options.ToString();
else
recvData = resData.Error.ToString();
}
else
{
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
}
logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:");
logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}");
}
///
/// 将所有数据输出到log中
///
/// void
public void PrintAllData()
{
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
///
/// None
public void Start()
{
try
{
listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
}
}
///
/// Close UDP Server
///
/// None
public void Stop()
{
listener.Close();
}
}