diff --git a/server/src/ArpClient.cs b/server/src/ArpClient.cs index 4172ac9..3d35969 100644 --- a/server/src/ArpClient.cs +++ b/server/src/ArpClient.cs @@ -82,7 +82,9 @@ public static class Arp try { - string command = GetArpAddCommand(ipAddress, macAddress, interfaceName); + // 格式化 MAC 地址以适配不同操作系统 + string formattedMac = FormatMacAddress(macAddress); + string command = GetArpAddCommand(ipAddress, formattedMac, interfaceName); var result = await ExecuteCommandAsync(command); return result.IsSuccess; } @@ -359,8 +361,19 @@ public static class Arp /// private static ArpEntry? ParseWindowsArpEntry(string line) { + // 跳过空行和标题行 + if (string.IsNullOrWhiteSpace(line) || + line.Contains("Interface:") || + line.Contains("Internet Address") || + line.Contains("Physical Address") || + line.Contains("Type")) + { + return null; + } + // Windows arp -a 输出格式: IP地址 物理地址 类型 - var pattern = @"(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9-]{17})\s+(\w+)"; + // 示例: 172.6.0.1 e4-3a-6e-29-c3-5b dynamic + var pattern = @"^\s*(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9-]{17})\s+(\w+)\s*$"; var match = Regex.Match(line, pattern); if (match.Success) @@ -368,7 +381,7 @@ public static class Arp return new ArpEntry { IpAddress = match.Groups[1].Value, - MacAddress = match.Groups[2].Value.Replace('-', ':'), + MacAddress = FormatMacAddress(match.Groups[2].Value), // 格式化 MAC 地址 Type = match.Groups[3].Value }; } @@ -391,7 +404,7 @@ public static class Arp { Hostname = match.Groups[1].Value, IpAddress = match.Groups[2].Value, - MacAddress = match.Groups[3].Value, + MacAddress = FormatMacAddress(match.Groups[3].Value), // 格式化 MAC 地址 Type = match.Groups[5].Value, Interface = match.Groups[6].Value }; @@ -406,7 +419,7 @@ public static class Arp return new ArpEntry { IpAddress = simpleMatch.Groups[1].Value, - MacAddress = simpleMatch.Groups[2].Value, + MacAddress = FormatMacAddress(simpleMatch.Groups[2].Value), // 格式化 MAC 地址 Interface = simpleMatch.Groups[3].Value }; } @@ -448,8 +461,11 @@ public static class Arp if (string.IsNullOrWhiteSpace(macAddress)) throw new ArgumentException("MAC 地址不能为空", nameof(macAddress)); + // 格式化 MAC 地址以适配不同操作系统 + string formattedMac = FormatMacAddress(macAddress); + var entry = await GetArpEntryAsync(ipAddress); - if (entry != null && string.Equals(entry.MacAddress, macAddress, StringComparison.OrdinalIgnoreCase)) + if (entry != null && string.Equals(FormatMacAddress(entry.MacAddress), formattedMac, StringComparison.OrdinalIgnoreCase)) { // 已存在且 MAC 匹配,无需操作 return true; @@ -462,7 +478,33 @@ public static class Arp } // 新增 ARP 记录 - return await AddArpEntryAsync(ipAddress, macAddress, interfaceName); + return await AddArpEntryAsync(ipAddress, formattedMac, interfaceName); + } + + /// + /// 格式化 MAC 地址为指定平台格式 + /// + /// 原始 MAC 地址 + /// 格式化后的 MAC 地址 + public static string FormatMacAddress(string macAddress) + { + if (string.IsNullOrWhiteSpace(macAddress)) + return string.Empty; + + var cleaned = macAddress.Replace("-", "").Replace(":", "").ToLowerInvariant(); + if (cleaned.Length != 12) + return macAddress; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Windows: XX-XX-XX-XX-XX-XX + return string.Join("-", Enumerable.Range(0, 6).Select(i => cleaned.Substring(i * 2, 2))); + } + else + { + // Unix/Linux/macOS: xx:xx:xx:xx:xx:xx + return string.Join(":", Enumerable.Range(0, 6).Select(i => cleaned.Substring(i * 2, 2))); + } } } /// diff --git a/server/src/Controllers/NetConfigController.cs b/server/src/Controllers/NetConfigController.cs index e62313a..3adda80 100644 --- a/server/src/Controllers/NetConfigController.cs +++ b/server/src/Controllers/NetConfigController.cs @@ -16,9 +16,167 @@ public class NetConfigController : ControllerBase { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); - // 固定的实验板IP和端口 + // 固定的实验板IP,端口,MAC地址 private const string BOARD_IP = "169.254.109.0"; private const int BOARD_PORT = 1234; + private const string BOARD_MAC = "12:34:56:78:9a:bc"; + + // 本机网络信息 + private readonly IPAddress _localIP; + private readonly byte[] _localMAC; + private readonly string _localIPString; + private readonly string _localMACString; + private readonly string _localInterface; + + public NetConfigController() + { + // 初始化本机IP地址 + _localIP = GetLocalIPAddress(); + _localIPString = _localIP?.ToString() ?? "未知"; + + // 初始化本机MAC地址 + _localMAC = GetLocalMACAddress(); + _localMACString = _localMAC != null ? BitConverter.ToString(_localMAC).Replace("-", ":") : "未知"; + + // 获取本机网络接口名称 + _localInterface = GetLocalNetworkInterface(); + + logger.Info($"NetConfigController 初始化完成 - 本机IP: {_localIPString}, 本机MAC: {_localMACString}, 接口: {_localInterface}"); + } + + /// + /// 获取本机IP地址(优先选择与实验板同网段的IP) + /// + /// 本机IP地址 + private IPAddress GetLocalIPAddress() + { + try + { + var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray(); + + // 优先选择与实验板IP前三段相同的IP + var sameSegmentIP = System.Net.NetworkInformation.NetworkInterface + .GetAllNetworkInterfaces() + .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up + && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) + .SelectMany(nic => nic.GetIPProperties().UnicastAddresses) + .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + .Select(addr => addr.Address) + .FirstOrDefault(addr => + { + var segments = addr.ToString().Split('.'); + return segments.Length == 4 && + segments[0] == boardIpSegments[0] && + segments[1] == boardIpSegments[1] && + segments[2] == boardIpSegments[2]; + }); + + if (sameSegmentIP != null) + return sameSegmentIP; + + // 如果没有找到同网段的IP,返回第一个可用的IP + return System.Net.NetworkInformation.NetworkInterface + .GetAllNetworkInterfaces() + .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up + && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) + .SelectMany(nic => nic.GetIPProperties().UnicastAddresses) + .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + .Select(addr => addr.Address) + .FirstOrDefault() ?? IPAddress.Loopback; + } + catch (Exception ex) + { + logger.Error(ex, "获取本机IP地址失败"); + return IPAddress.Loopback; + } + } + + /// + /// 获取本机MAC地址 + /// + /// 本机MAC地址字节数组 + private byte[] GetLocalMACAddress() + { + try + { + return System.Net.NetworkInformation.NetworkInterface + .GetAllNetworkInterfaces() + .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up + && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) + .Select(nic => nic.GetPhysicalAddress()?.GetAddressBytes()) + .FirstOrDefault(bytes => bytes != null && bytes.Length == 6) ?? new byte[6]; + } + catch (Exception ex) + { + logger.Error(ex, "获取本机MAC地址失败"); + return new byte[6]; + } + } + + /// + /// 获取本机网络接口名称 + /// + /// 网络接口名称 + private string GetLocalNetworkInterface() + { + try + { + var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray(); + + // 优先选择与实验板IP前三段相同的网络接口 + var sameSegmentInterface = System.Net.NetworkInformation.NetworkInterface + .GetAllNetworkInterfaces() + .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up + && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) + .FirstOrDefault(nic => + { + var ipAddresses = nic.GetIPProperties().UnicastAddresses + .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + .Select(addr => addr.Address); + + return ipAddresses.Any(addr => + { + var segments = addr.ToString().Split('.'); + return segments.Length == 4 && + segments[0] == boardIpSegments[0] && + segments[1] == boardIpSegments[1] && + segments[2] == boardIpSegments[2]; + }); + }); + + if (sameSegmentInterface != null) + return sameSegmentInterface.Name; + + // 如果没有找到同网段的接口,返回第一个可用的接口 + return System.Net.NetworkInformation.NetworkInterface + .GetAllNetworkInterfaces() + .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up + && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) + .FirstOrDefault()?.Name ?? "未知"; + } + catch (Exception ex) + { + logger.Error(ex, "获取本机网络接口名称失败"); + return "未知"; + } + } + + /// + /// 初始化ARP记录 + /// + /// 是否成功 + private async Task InitializeArpAsync() + { + try + { + return await Arp.CheckOrAddAsync(BOARD_IP, BOARD_MAC, _localInterface); + } + catch (Exception ex) + { + logger.Error(ex, "初始化ARP记录失败"); + return false; + } + } /// /// 获取主机IP地址 @@ -32,11 +190,12 @@ public class NetConfigController : ControllerBase { try { - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.GetHostIP(); if (!result.IsSuccessful) @@ -66,11 +225,12 @@ public class NetConfigController : ControllerBase { try { - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.GetBoardIP(); if (!result.IsSuccessful) @@ -100,11 +260,12 @@ public class NetConfigController : ControllerBase { try { - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.GetHostMAC(); if (!result.IsSuccessful) @@ -134,11 +295,12 @@ public class NetConfigController : ControllerBase { try { - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.GetBoardMAC(); if (!result.IsSuccessful) @@ -168,12 +330,13 @@ public class NetConfigController : ControllerBase { try { - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); + var hostIPResult = await netConfig.GetHostIP(); var boardIPResult = await netConfig.GetBoardIP(); var hostMACResult = await netConfig.GetHostMAC(); @@ -255,12 +418,12 @@ public class NetConfigController : ControllerBase try { - // 创建网络配置客户端 - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.SetHostIP(hostIpAddress); if (!result.IsSuccessful) @@ -298,12 +461,12 @@ public class NetConfigController : ControllerBase try { - // 创建网络配置客户端 - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.SetBoardIP(newIpAddress); if (!result.IsSuccessful) @@ -342,12 +505,12 @@ public class NetConfigController : ControllerBase try { - // 创建网络配置客户端 - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); var result = await netConfig.SetHostMAC(macBytes); if (!result.IsSuccessful) @@ -377,33 +540,16 @@ public class NetConfigController : ControllerBase { try { - // 获取所有本机IPv4地址,并选择与实验板IP前三段相同的IP - var boardIpSegments = BOARD_IP.Split('.').Take(3).ToArray(); - var ip = System.Net.NetworkInformation.NetworkInterface - .GetAllNetworkInterfaces() - .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up - && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) - .SelectMany(nic => nic.GetIPProperties().UnicastAddresses) - .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) - .Select(addr => addr.Address) - .FirstOrDefault(addr => - { - var segments = addr.ToString().Split('.'); - return segments.Length == 4 && - segments[0] == boardIpSegments[0] && - segments[1] == boardIpSegments[1] && - segments[2] == boardIpSegments[2]; - }); - - if (ip == null) + if (_localIP == null) return StatusCode(StatusCodes.Status500InternalServerError, "无法获取本机IP地址"); - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } - var result = await netConfig.SetHostIP(ip); + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); + var result = await netConfig.SetHostIP(_localIP); if (!result.IsSuccessful) { @@ -431,27 +577,18 @@ public class NetConfigController : ControllerBase [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task UpdateHostMAC() { - byte[]? macBytes = null; try { - // 获取本机第一个可用的MAC地址 - macBytes = System.Net.NetworkInformation.NetworkInterface - .GetAllNetworkInterfaces() - .Where(nic => nic.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up - && nic.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback) - .Select(nic => nic.GetPhysicalAddress()?.GetAddressBytes()) - .FirstOrDefault(bytes => bytes != null && bytes.Length == 6); - - if (macBytes == null) + if (_localMAC == null || _localMAC.Length != 6) return StatusCode(StatusCodes.Status500InternalServerError, "无法获取本机MAC地址"); - // 创建网络配置客户端 - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) + if (!(await InitializeArpAsync())) { - throw new Exception($"无法配置ARP"); + throw new Exception("无法配置ARP记录"); } - var result = await netConfig.SetHostMAC(macBytes); + + var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); + var result = await netConfig.SetHostMAC(_localMAC); if (!result.IsSuccessful) { @@ -469,47 +606,20 @@ public class NetConfigController : ControllerBase } /// - /// 设置板卡MAC地址 + /// 获取本机网络信息 /// - /// 板卡MAC地址(格式:AA:BB:CC:DD:EE:FF) - /// 操作结果 - [HttpPost("SetBoardMAC")] + /// 本机网络信息 + [HttpGet("GetLocalNetworkInfo")] [EnableCors("Users")] - [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status500InternalServerError)] - public async Task SetBoardMAC(string boardMac) + [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] + public IActionResult GetLocalNetworkInfo() { - if (string.IsNullOrWhiteSpace(boardMac)) - return BadRequest("板卡MAC地址不能为空"); - - // 解析MAC地址 - if (!TryParseMacAddress(boardMac, out var macBytes)) - return BadRequest("MAC地址格式不正确,请使用格式:AA:BB:CC:DD:EE:FF"); - - try + return Ok(new { - // 创建网络配置客户端 - var netConfig = new NetConfig(BOARD_IP, BOARD_PORT, 0); - if (!(await netConfig.Init())) - { - throw new Exception($"无法配置ARP"); - } - var result = await netConfig.SetBoardMAC(macBytes); - - if (!result.IsSuccessful) - { - logger.Error($"设置板卡MAC地址失败: {result.Error}"); - return StatusCode(StatusCodes.Status500InternalServerError, $"设置失败: {result.Error}"); - } - - return Ok(result.Value); - } - catch (Exception ex) - { - logger.Error(ex, "设置板卡MAC地址时发生异常"); - return StatusCode(StatusCodes.Status500InternalServerError, "设置失败,请稍后重试"); - } + LocalIP = _localIPString, + LocalMAC = _localMACString, + LocalInterface = _localInterface + }); } /// diff --git a/server/src/Peripherals/NetConfigClient.cs b/server/src/Peripherals/NetConfigClient.cs index 9115a68..b90c200 100644 --- a/server/src/Peripherals/NetConfigClient.cs +++ b/server/src/Peripherals/NetConfigClient.cs @@ -26,8 +26,6 @@ public class NetConfig readonly string address; private IPEndPoint ep; - const string DEFAULT_BOARD_MAC = "12:34:56:78:9a:bc"; - /// /// Initialize NetConfig client /// @@ -46,15 +44,6 @@ public class NetConfig this.timeout = timeout; } - /// - /// [TODO:description] - /// - /// [TODO:return] - public async ValueTask Init() - { - return await Arp.CheckOrAddAsync(this.address, DEFAULT_BOARD_MAC); - } - /// /// Set host IP address ///