diff --git a/server/src/ArpClient.cs b/server/src/ArpClient.cs
new file mode 100644
index 0000000..6a806df
--- /dev/null
+++ b/server/src/ArpClient.cs
@@ -0,0 +1,421 @@
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+
+///
+/// ARP 记录管理静态类(跨平台支持)
+///
+public static class Arp
+{
+ ///
+ /// 读取所有 ARP 记录
+ ///
+ /// ARP 记录列表
+ public static async Task> GetArpTableAsync()
+ {
+ var entries = new List();
+
+ try
+ {
+ string command = GetArpListCommand();
+ var result = await ExecuteCommandAsync(command);
+ if (result.IsSuccess)
+ {
+ var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (var line in lines)
+ {
+ var entry = ParseArpEntry(line);
+ if (entry != null)
+ {
+ entries.Add(entry);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"读取 ARP 表失败: {ex.Message}");
+ }
+
+ return entries;
+ }
+
+ ///
+ /// 添加 ARP 记录
+ ///
+ /// IP 地址
+ /// MAC 地址
+ /// 网络接口名称(可选)
+ /// 是否成功
+ public static async Task AddArpEntryAsync(string ipAddress, string macAddress, string interfaceName = null)
+ {
+ if (string.IsNullOrWhiteSpace(ipAddress))
+ throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
+
+ if (string.IsNullOrWhiteSpace(macAddress))
+ throw new ArgumentException("MAC 地址不能为空", nameof(macAddress));
+
+ try
+ {
+ string command = GetArpAddCommand(ipAddress, macAddress, interfaceName);
+ var result = await ExecuteCommandAsync(command);
+ return result.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"添加 ARP 记录失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 删除 ARP 记录
+ ///
+ /// 要删除的 IP 地址
+ /// 网络接口名称(可选)
+ /// 是否成功
+ public static async Task DeleteArpEntryAsync(string ipAddress, string interfaceName = null)
+ {
+ if (string.IsNullOrWhiteSpace(ipAddress))
+ throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
+
+ try
+ {
+ string command = GetArpDeleteCommand(ipAddress, interfaceName);
+ var result = await ExecuteCommandAsync(command);
+ return result.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"删除 ARP 记录失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 清空所有 ARP 记录
+ ///
+ /// 是否成功
+ public static async Task ClearArpTableAsync()
+ {
+ try
+ {
+ string command = GetArpClearCommand();
+ var result = await ExecuteCommandAsync(command);
+ return result.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"清空 ARP 表失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 查询特定 IP 的 ARP 记录
+ ///
+ /// IP 地址
+ /// ARP 记录,如果不存在则返回 null
+ public static async Task GetArpEntryAsync(string ipAddress)
+ {
+ if (string.IsNullOrWhiteSpace(ipAddress))
+ throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
+
+ try
+ {
+ string command = GetArpQueryCommand(ipAddress);
+ var result = await ExecuteCommandAsync(command);
+ if (result.IsSuccess)
+ {
+ var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var entry = ParseArpEntry(line);
+ if (entry != null && entry.IpAddress == ipAddress)
+ {
+ return entry;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"查询 ARP 记录失败: {ex.Message}");
+ }
+
+ return null;
+ }
+
+ ///
+ /// 获取 ARP 列表命令
+ ///
+ private static string GetArpListCommand()
+ {
+ return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ ? "arp -a"
+ : "arp -a";
+ }
+
+ ///
+ /// 获取 ARP 添加命令
+ ///
+ private static string GetArpAddCommand(string ipAddress, string macAddress, string interfaceName)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return string.IsNullOrWhiteSpace(interfaceName)
+ ? $"arp -s {ipAddress} {macAddress}"
+ : $"arp -s {ipAddress} {macAddress} {interfaceName}";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return string.IsNullOrWhiteSpace(interfaceName)
+ ? $"arp -s {ipAddress} {macAddress}"
+ : $"arp -s {ipAddress} {macAddress} -i {interfaceName}";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return string.IsNullOrWhiteSpace(interfaceName)
+ ? $"arp -s {ipAddress} {macAddress}"
+ : $"arp -s {ipAddress} {macAddress} ifscope {interfaceName}";
+ }
+ else
+ {
+ throw new PlatformNotSupportedException("不支持的操作系统平台");
+ }
+ }
+
+ ///
+ /// 获取 ARP 删除命令
+ ///
+ private static string GetArpDeleteCommand(string ipAddress, string interfaceName)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return $"arp -d {ipAddress}";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return string.IsNullOrWhiteSpace(interfaceName)
+ ? $"arp -d {ipAddress}"
+ : $"arp -d {ipAddress} -i {interfaceName}";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return string.IsNullOrWhiteSpace(interfaceName)
+ ? $"arp -d {ipAddress}"
+ : $"arp -d {ipAddress} ifscope {interfaceName}";
+ }
+ else
+ {
+ throw new PlatformNotSupportedException("不支持的操作系统平台");
+ }
+ }
+
+ ///
+ /// 获取 ARP 清空命令
+ ///
+ private static string GetArpClearCommand()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return "arp -d *";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return "ip neigh flush all";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return "arp -d -a";
+ }
+ else
+ {
+ throw new PlatformNotSupportedException("不支持的操作系统平台");
+ }
+ }
+
+ ///
+ /// 获取 ARP 查询命令
+ ///
+ private static string GetArpQueryCommand(string ipAddress)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return $"arp -a {ipAddress}";
+ }
+ else
+ {
+ return $"arp -n {ipAddress}";
+ }
+ }
+
+ ///
+ /// 执行系统命令
+ ///
+ /// 命令
+ /// 命令执行结果
+ private static async Task ExecuteCommandAsync(string command)
+ {
+ try
+ {
+ ProcessStartInfo processInfo;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ processInfo = new ProcessStartInfo
+ {
+ FileName = "cmd.exe",
+ Arguments = $"/c {command}",
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+ }
+ else
+ {
+ processInfo = new ProcessStartInfo
+ {
+ FileName = "/bin/bash",
+ Arguments = $"-c \"{command}\"",
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ };
+ }
+
+ using var process = new Process { StartInfo = processInfo };
+ process.Start();
+
+ var output = await process.StandardOutput.ReadToEndAsync();
+ var error = await process.StandardError.ReadToEndAsync();
+
+ await process.WaitForExitAsync();
+
+ return new CommandResult
+ {
+ IsSuccess = process.ExitCode == 0,
+ Output = output,
+ Error = error,
+ ExitCode = process.ExitCode
+ };
+ }
+ catch (Exception ex)
+ {
+ return new CommandResult
+ {
+ IsSuccess = false,
+ Error = ex.Message,
+ ExitCode = -1
+ };
+ }
+ }
+
+ ///
+ /// 解析 ARP 记录行
+ ///
+ /// ARP 记录行
+ /// 解析后的 ARP 记录
+ private static ArpEntry? ParseArpEntry(string line)
+ {
+ if (string.IsNullOrWhiteSpace(line))
+ return null;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return ParseWindowsArpEntry(line);
+ }
+ else
+ {
+ return ParseUnixArpEntry(line);
+ }
+ }
+
+ ///
+ /// 解析 Windows ARP 记录
+ ///
+ private static ArpEntry? ParseWindowsArpEntry(string line)
+ {
+ // Windows arp -a 输出格式: IP地址 物理地址 类型
+ var pattern = @"(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9-]{17})\s+(\w+)";
+ var match = Regex.Match(line, pattern);
+
+ if (match.Success)
+ {
+ return new ArpEntry
+ {
+ IpAddress = match.Groups[1].Value,
+ MacAddress = match.Groups[2].Value.Replace('-', ':'),
+ Type = match.Groups[3].Value
+ };
+ }
+
+ return null;
+ }
+
+ ///
+ /// 解析 Unix/Linux ARP 记录
+ ///
+ private static ArpEntry? ParseUnixArpEntry(string line)
+ {
+ // Unix/Linux arp -a 输出格式: hostname (ip) at mac [ether] on interface
+ var pattern = @"(\S+)\s+\((\d+\.\d+\.\d+\.\d+)\)\s+at\s+([a-fA-F0-9:]{17})\s+\[(\w+)\]\s+on\s+(\S+)";
+ var match = Regex.Match(line, pattern);
+
+ if (match.Success)
+ {
+ return new ArpEntry
+ {
+ Hostname = match.Groups[1].Value,
+ IpAddress = match.Groups[2].Value,
+ MacAddress = match.Groups[3].Value,
+ Type = match.Groups[4].Value,
+ Interface = match.Groups[5].Value
+ };
+ }
+
+ // 匹配简单格式: ip mac interface
+ var simplePattern = @"(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9:]{17})\s+(\S+)";
+ var simpleMatch = Regex.Match(line, simplePattern);
+
+ if (simpleMatch.Success)
+ {
+ return new ArpEntry
+ {
+ IpAddress = simpleMatch.Groups[1].Value,
+ MacAddress = simpleMatch.Groups[2].Value,
+ Interface = simpleMatch.Groups[3].Value
+ };
+ }
+
+ return null;
+ }
+}
+
+///
+/// ARP 记录条目
+///
+public class ArpEntry
+{
+ public string Hostname { get; set; } = string.Empty;
+ public string IpAddress { get; set; } = string.Empty;
+ public string MacAddress { get; set; } = string.Empty;
+ public string Type { get; set; } = string.Empty;
+ public string Interface { get; set; } = string.Empty;
+
+ public override string ToString()
+ {
+ return $"{IpAddress} -> {MacAddress} ({Interface})";
+ }
+}
+
+///
+/// 命令执行结果
+///
+public class CommandResult
+{
+ public bool IsSuccess { get; set; }
+ public string Output { get; set; } = string.Empty;
+ public string Error { get; set; } = string.Empty;
+ public int ExitCode { get; set; }
+}
diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs
index f5d9323..70a9cc6 100644
--- a/server/src/UdpServer.cs
+++ b/server/src/UdpServer.cs
@@ -585,242 +585,6 @@ public class UDPServer
}
}
- // 强制进行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;
- }
-
- 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 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;
- }
}
///