using System.Collections.Concurrent;
using System.Net;
using System.Net.NetworkInformation; // 添加这个引用
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using DotNext;
using Newtonsoft.Json;
using WebProtocol;
/// UDP接受数据包格式
public class UDPData
{
///
/// 接受到的时间
///
public required DateTime DateTime { get; set; }
///
/// 发送来源的IP地址
///
public required string Address { get; set; }
///
/// 发送来源的端口号
///
public required int Port { get; set; }
///
/// 任务ID
///
public required int TaskID { 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,
TaskID = this.TaskID,
Data = cloneData,
HasRead = this.HasRead
};
}
///
/// 将UDP Data 转化为Json 格式字符串
///
/// json字符串
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
///
/// UDP 服务器
///
public class UDPServer : IDisposable
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private ConcurrentDictionary> udpData = new ConcurrentDictionary>();
private readonly ReaderWriterLockSlim udpDataLock = new ReaderWriterLockSlim();
private int listenPort;
private List listeners = new List();
private IPEndPoint groupEP;
private bool isRunning = false;
private bool disposed = false;
///
/// 是否正在工作
///
public bool IsRunning { get { return isRunning; } }
/// UDP 服务器的错误代码
public enum ErrorCode
{
/// [TODO:description]
Success = 0,
/// [TODO:description]
GetNoneAfterTimeout,
/// [TODO:description]
ResponseWrong,
/// [TODO:description]
NotRecvDataPackage,
}
///
/// Construct a udp server with fixed port
///
/// Device UDP Port
/// UDP Client Num
/// UDPServer class
public UDPServer(int port, int num)
{
// Construction
this.listenPort = port;
try
{
for (int i = 0; i < num; i++)
{
listeners.Add(new UdpClient(this.listenPort + i));
}
this.groupEP = new IPEndPoint(IPAddress.Any, listenPort);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw new ArgumentException(
$"Failed to set up server with this port: {port}",
nameof(port)
);
}
}
///
/// 异步寻找目标发送的内容
///
/// 目标IP地址
/// [TODO:parameter]
/// 超时时间
/// 延迟时间
/// 调用函数名称
/// 调用函数位置
///
/// 异步Optional 数据包:
/// Optional 为空时,表明找不到数据;
/// Optional 存在时,为最先收到的数据
///
public async ValueTask> FindDataAsync(
string ipAddr, int taskID, int timeout = 1000, int cycle = 0,
[CallerMemberName] string callerName = "",
[CallerLineNumber] int callerLineNum = 0
)
{
UDPData? data = null;
var startTime = DateTime.Now;
var isTimeout = false;
while (!isTimeout)
{
var elapsed = DateTime.Now - startTime;
isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
if (isTimeout) break;
udpDataLock.EnterWriteLock();
try
{
var key = $"{ipAddr}-{taskID}";
if (udpData.TryGetValue(key, out var sortedList) && sortedList.Count > 0)
{
// 获取最早的数据(第一个元素)
var firstKey = sortedList.Keys[0];
data = sortedList[firstKey];
sortedList.RemoveAt(0);
break;
}
}
finally
{
udpDataLock.ExitWriteLock();
}
await Task.Delay(cycle);
}
if (data is null)
{
logger.Trace("Get nothing even after time out");
return new(null);
}
else
{
return new(data.DeepClone());
}
}
///
/// 异步寻找目标发送的所有内容,并清空队列
///
/// 目标IP地址
/// 任务ID
/// 超时时间
/// 异步Optional 数据包列表
public async ValueTask>> FindDataArrayAsync(string ipAddr, int taskID, int timeout = 1000)
{
List? data = null;
var startTime = DateTime.Now;
var isTimeout = false;
while (!isTimeout)
{
var elapsed = DateTime.Now - startTime;
isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
if (isTimeout) break;
udpDataLock.EnterWriteLock();
try
{
var key = $"{ipAddr}-{taskID}";
if (udpData.TryGetValue(key, out var sortedList) && sortedList.Count > 0)
{
data = new List(sortedList.Values);
// 输出数据
// PrintDataArray(data);
sortedList.Clear();
break;
}
}
finally
{
udpDataLock.ExitWriteLock();
}
}
if (data is null)
{
logger.Trace("Get nothing even after time out");
return new(null);
}
else
{
return new(data);
}
}
///
/// 获取还未被读取的数据列表
///
/// IP地址
/// 任务ID
/// 超时时间
/// 数据列表
public async ValueTask>> GetDataArrayAsync(string ipAddr, int taskID, int timeout = 1000)
{
List? data = null;
var startTime = DateTime.Now;
var isTimeout = false;
while (!isTimeout)
{
var elapsed = DateTime.Now - startTime;
isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
if (isTimeout) break;
udpDataLock.EnterReadLock();
try
{
var key = $"{ipAddr}-{taskID}";
if (udpData.TryGetValue(key, out var sortedList) && sortedList.Count > 0)
{
data = new List(sortedList.Values);
break;
}
}
finally
{
udpDataLock.ExitReadLock();
}
}
if (data is null)
{
logger.Trace("Get nothing even after time out");
return new(null);
}
else
{
return new(data);
}
}
///
/// 异步获取指定IP和任务ID的数据队列长度
///
/// IP地址
/// 任务ID
/// 超时时间
/// 数据队列长度
public async ValueTask> GetDataCountAsync(string ipAddr, int taskID, int timeout = 1000)
{
int? count = null;
var startTime = DateTime.Now;
var isTimeout = false;
while (!isTimeout)
{
var elapsed = DateTime.Now - startTime;
isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
if (isTimeout) break;
udpDataLock.EnterReadLock();
try
{
var key = $"{ipAddr}-{taskID}";
if (udpData.TryGetValue(key, out var sortedList))
{
count = sortedList.Count;
break;
}
}
finally
{
udpDataLock.ExitReadLock();
}
}
if (count is null)
{
logger.Trace("Get nothing even after time out");
return Optional.None;
}
else
{
return new(count.Value);
}
}
///
/// 异步等待写响应
///
/// IP地址
/// [TODO:parameter]
/// UDP 端口
/// 超时时间范围
/// 接收响应包
public async ValueTask> WaitForAckAsync
(string address, int taskID, int port = -1, int timeout = 1000)
{
var data = await FindDataAsync(address, taskID, timeout);
if (!data.HasValue)
return new(new Exception("Get None even after time out!"));
var recvData = data.Value;
if (recvData.Address != address || (port > 0 && recvData.Port != port))
return new(new Exception("Receive Data From Wrong Board!"));
var retPack = WebProtocol.RecvRespPackage.FromBytes(recvData.Data);
if (!retPack.IsSuccessful)
return new(new Exception("Not RecvDataPackage!", retPack.Error));
return retPack.Value;
}
///
/// 异步等待数据
///
/// IP地址
/// [TODO:parameter]
/// UDP 端口
/// 超时时间范围
/// 接收数据包
public async ValueTask> WaitForDataAsync
(string address, int taskID, int port = -1, int timeout = 1000)
{
var data = await FindDataAsync(address, taskID, timeout);
if (!data.HasValue)
return new(new Exception("Get None even after time out!"));
var recvData = data.Value;
if (recvData.Address != address || (port >= 0 && recvData.Port != port))
return new(new Exception("Receive Data From Wrong Board!"));
var retPack = WebProtocol.RecvDataPackage.FromBytes(recvData.Data);
if (!retPack.IsSuccessful)
return new(new Exception("Not RecvDataPackage!", retPack.Error));
return retPack.Value;
}
private async Task ReceiveHandler(byte[] data, IPEndPoint endPoint, DateTime time)
{
// 异步锁保护 udpData
await Task.Run(() =>
{
try
{
// Handle RemoteEP
if (endPoint is null)
{
logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
logger.Debug($" Original Data : {BitConverter.ToString(data).Replace("-", " ")}");
return;
}
var udpDataObj = RecordUDPData(data, endPoint, time, Convert.ToInt32(data[1]));
// PrintData(udpDataObj);
}
catch (Exception e)
{
logger.Error($"Got Error when handle receive:{e}");
}
});
}
private UDPData RecordUDPData(byte[] bytes, IPEndPoint remoteEP, DateTime time, int taskID)
{
var remoteAddress = remoteEP.Address.ToString();
var remotePort = remoteEP.Port;
var data = new UDPData()
{
Address = remoteAddress,
Port = remotePort,
TaskID = taskID,
Data = bytes,
DateTime = time,
HasRead = false,
};
udpDataLock.EnterWriteLock();
try
{
var key = $"{remoteAddress}-{taskID}";
var sortedList = udpData.GetOrAdd(key, _ => new SortedList());
// 处理相同时间戳的情况,添加微小的时间差
var uniqueTime = time;
while (sortedList.ContainsKey(uniqueTime))
{
logger.Warn(
$"Duplicate timestamp detected for {remoteAddress}:{remotePort} at {uniqueTime}.");
uniqueTime = uniqueTime.AddTicks(1);
}
sortedList.Add(uniqueTime, data);
// 输出单个数据
PrintData(data);
// 输出全部数据
// PrintAllData();
}
finally
{
udpDataLock.ExitWriteLock();
}
return data;
}
///
/// 输出UDP Data到log中
///
/// UDP数据
public string 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}");
return $@"
Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:
Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}
Decoded Data : {recvData}
";
}
///
/// 输出UDP Data数组到log中
///
/// UDP数据列表
public void PrintDataArray(IEnumerable dataArray)
{
foreach (var data in dataArray)
{
logger.Debug(PrintData(data));
}
}
///
/// 将所有数据输出到log中
///
/// void
public void PrintAllData()
{
logger.Debug("Ready Data:");
udpDataLock.EnterReadLock();
try
{
foreach (var kvp in udpData)
{
foreach (var data in kvp.Value.Values)
{
logger.Debug(PrintData(data));
}
}
}
finally
{
udpDataLock.ExitReadLock();
}
}
///
/// 清空指定IP地址的数据
///
/// IP地址
/// [TODO:parameter]
/// 无
public void ClearUDPData(string ipAddr, int taskID)
{
var key = $"{ipAddr}-{taskID}";
udpDataLock.EnterWriteLock();
try
{
if (udpData.TryGetValue(key, out var sortedList))
{
sortedList.Clear();
}
}
finally
{
udpDataLock.ExitWriteLock();
}
// 强制进行ARP刷新,防止后续传输时造成影响
FlushArpEntry(ipAddr);
}
///
/// 跨平台ARP缓存刷新
///
/// 目标IP地址
private void FlushArpEntry(string ipAddr)
{
try
{
// 验证IP地址格式
if (!IPAddress.TryParse(ipAddr, out var _))
{
logger.Warn($"Invalid IP address format: {ipAddr}");
return;
}
// 异步执行ARP刷新,避免阻塞主线程
Task.Run(() => ExecuteArpFlush(ipAddr));
}
catch (Exception ex)
{
logger.Error($"Error during ARP cache flush for {ipAddr}: {ex.Message}");
}
}
///
/// 使用Ping类重新刷新ARP缓存
///
/// 目标IP地址
private async void RefreshArpWithPing(string ipAddr)
{
try
{
using var ping = new Ping();
var options = new PingOptions
{
DontFragment = true,
Ttl = 32,
};
// 创建32字节的数据包
byte[] buffer = new byte[32];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(i % 256);
}
// 异步发送ping,100ms超时
var reply = await ping.SendPingAsync(ipAddr, 100, buffer, options);
if (reply.Status == IPStatus.Success)
{
logger.Debug($"ARP cache refreshed successfully for {ipAddr} (RTT: {reply.RoundtripTime}ms)");
}
else
{
logger.Warn($"Ping to {ipAddr} failed with status: {reply.Status}, but ARP entry should still be updated");
}
}
catch (Exception ex)
{
logger.Error($"Error refreshing ARP with ping for {ipAddr}: {ex.Message}");
}
}
///
/// 执行ARP刷新流程:先删除ARP条目,再用ping重新刷新
///
/// 目标IP地址
private async void ExecuteArpFlush(string ipAddr)
{
try
{
// 第一步:删除ARP条目
bool deleteSuccess = DeleteArpEntry(ipAddr);
if (deleteSuccess)
{
logger.Debug($"ARP entry deleted successfully for {ipAddr}");
// 第二步:使用Ping类重新刷新ARP缓存
RefreshArpWithPing(ipAddr);
}
else
{
logger.Warn($"Failed to delete ARP entry for {ipAddr}, but continuing with ping refresh");
// 即使删除失败,也尝试ping刷新
RefreshArpWithPing(ipAddr);
}
}
catch (Exception ex)
{
logger.Error($"Failed to execute ARP flush for {ipAddr}: {ex.Message}");
}
}
///
/// 删除ARP条目
///
/// 目标IP地址
/// 是否成功删除
private bool DeleteArpEntry(string ipAddr)
{
try
{
string command;
string arguments;
if (OperatingSystem.IsWindows())
{
// Windows: arp -d
command = "arp";
arguments = $"-d {ipAddr}";
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
// Linux/macOS: 优先使用 ip 命令删除
if (IsCommandAvailable("ip"))
{
command = "ip";
arguments = $"neigh del {ipAddr}";
}
else if (IsCommandAvailable("arp"))
{
command = "arp";
arguments = $"-d {ipAddr}";
}
else
{
logger.Warn("Neither 'ip' nor 'arp' command is available for ARP entry deletion");
return false;
}
}
else
{
logger.Warn($"Unsupported operating system for ARP entry deletion");
return false;
}
return ExecuteCommand(command, arguments, $"delete ARP entry for {ipAddr}");
}
catch (Exception ex)
{
logger.Error($"Error deleting ARP entry for {ipAddr}: {ex.Message}");
return false;
}
}
///
/// 检查系统命令是否可用
///
/// 命令名称
/// 命令是否可用
private bool IsCommandAvailable(string command)
{
try
{
var process = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? "where" : "which",
Arguments = command,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
process.Start();
process.WaitForExit(1000); // 1秒超时
return process.ExitCode == 0;
}
catch
{
return false;
}
}
///
/// 执行系统命令
///
/// 命令
/// 参数
/// 操作描述
/// 是否成功执行
private bool ExecuteCommand(string command, string arguments, string operation)
{
try
{
var process = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = command,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
}
};
process.Start();
// 设置超时时间,避免进程挂起
if (process.WaitForExit(5000)) // 5秒超时
{
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
if (process.ExitCode == 0)
{
logger.Debug($"Command executed successfully: {operation}");
return true;
}
else
{
logger.Warn($"Command failed: {operation}. Exit code: {process.ExitCode}, Error: {error}");
return false;
}
}
else
{
process.Kill();
logger.Warn($"Command timed out: {operation}");
return false;
}
}
catch (Exception ex)
{
logger.Error($"Failed to execute command for {operation}: {ex.Message}");
return false;
}
}
///
/// Start UDP Server
///
/// None
public void Start()
{
this.isRunning = true;
try
{
foreach (var client in listeners)
{
Task.Run(() =>
{
while (this.isRunning)
{
try
{
var ep = new IPEndPoint(IPAddress.Any, listenPort);
var result = client.Receive(ref ep);
_ = ReceiveHandler(result, ep, DateTime.Now);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
});
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
this.isRunning = false;
}
}
///
/// Close UDP Server
///
/// None
public void Stop()
{
foreach (var item in listeners)
{
item.Close();
}
this.isRunning = false;
}
///
/// 释放资源
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
Stop();
udpDataLock?.Dispose();
}
disposed = true;
}
}
~UDPServer()
{
Dispose(false);
}
}