存在多块网络适配器时如何查找合适IP地址开启TCP/IP服务端口
C# 正确获取本机物理网卡互联网访问IP的实现方案
问题背景
原有实现仅通过网卡启用状态、IPV4协议、排除回环地址三个条件筛选IP,当设备存在Hyper-V、VirtualBox、VMware等创建的多块虚拟网卡时,会优先命中虚拟网卡IP,无法拿到实际用于访问互联网的物理网卡IP。
优化思路
- 过滤虚拟网卡:通过网卡描述的特征关键词,排除虚拟适配器、蓝牙、VPN、拨号类非物理网卡
- 校验网关存在:用于互联网访问的物理网卡必然配置了IPV4网关,无有效网关的网卡直接跳过
- 优先级排序:若存在多块符合条件的物理网卡,按路由跃点数升序排序,取跃点最低的IP作为最终结果,匹配系统默认路由规则
优化后实现代码
using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; public static IPAddress GetPhysicalInternetIP() { // 常见虚拟网卡特征关键词,可根据实际设备环境补充 var virtualNicKeywords = new[] { "Hyper-V", "VirtualBox", "VMware", "Virtual Adapter", "VPN", "WAN Miniport", "Bluetooth", "Microsoft Wi-Fi Direct", "Loopback", "TAP-Windows" }; var candidateIPs = new List<(IPAddress Address, int Metric)>(); foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) { // 跳过未启用、回环、隧道类网卡 if (nic.OperationalStatus != OperationalStatus.Up || nic.NetworkInterfaceType is NetworkInterfaceType.Loopback or NetworkInterfaceType.Tunnel) continue; // 匹配虚拟网卡关键词则直接跳过 string nicDesc = nic.Description; if (virtualNicKeywords.Any(keyword => nicDesc.Contains(keyword, StringComparison.OrdinalIgnoreCase))) continue; var ipProps = nic.GetIPProperties(); // 跳过无有效IPV4网关的网卡 if (!ipProps.GatewayAddresses.Any(g => g.Address.AddressFamily == AddressFamily.InterNetwork)) continue; foreach (var unicastIP in ipProps.UnicastAddresses) { // 仅保留IPV4非回环地址 if (unicastIP.Address.AddressFamily != AddressFamily.InterNetwork || IPAddress.IsLoopback(unicastIP.Address)) continue; // 记录IP及对应路由跃点,同网卡仅取第一个有效IP int metric = ipProps.GetIPv4Properties().RouteMetric; candidateIPs.Add((unicastIP.Address, metric)); break; } } // 按跃点升序排序,取优先级最高的IP return candidateIPs.OrderBy(x => x.Metric).FirstOrDefault().Address; }
注意事项
- 虚拟网卡关键词列表可根据实际设备环境调整,避免漏过滤或误识别物理网卡
- 若设备同时连接有线网络和WiFi,会自动返回系统默认优先使用的链路对应IP
- 如需获取IPV6地址,将代码中
AddressFamily.InterNetwork替换为AddressFamily.InterNetworkV6即可
内容的提问来源于stack exchange,提问作者Eric Ouellet
相关产品推荐
相关产品推荐

