应遍历启用的物理网卡并筛选有效IPv4地址,因Dns.GetHostAddresses常返回127.0.0.1(受hosts文件或DNS配置影响),而NetworkInterface.GetAllNetworkInterfaces可准确获取真实局域网IP。

别用 Dns.GetHostAddresses(Dns.GetHostName()) 拿本机 IP —— 它大概率返回 127.0.0.1 或 ::1,不是你想要的局域网地址。真正可靠的方案是遍历网卡,筛选启用状态、非回环、有有效 IPv4 地址的接口。
为什么 Dns.GetHostEntry 常常返回 127.0.0.1?
因为系统 hosts 文件或 DNS 配置把主机名映射到了本地回环地址(比如 Windows 的 C:\Windows\System32\drivers\etc\hosts 里写了 127.0.0.1 mypc)。这不是代码错,而是解析路径错了。
Dns.GetHostEntry 查的是“主机名到 IP”的映射关系,不反映真实网卡状态。它可能包含 IPv6 链路本地地址、隧道地址、甚至 0.0.0.0(DHCP 还没完成时),完全不可控。
怎么用 NetworkInterface.GetAllNetworkInterfaces 拿到真正的局域网 IPv4?
这是目前最稳定、跨平台兼容性最好的方式,核心逻辑是:查所有启用的物理网卡 → 提取其 IPv4 单播地址 → 排除回环、未分配、公网地址。 示例关键片段:
var ip = NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up
&& (nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet
|| nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211))
.SelectMany(nic => nic.GetIPProperties().UnicastAddresses)
.Where(ua => ua.Address.AddressFamily == AddressFamily.InterNetwork
&& !ua.Address.IsIPv4Private() == false // 注意:IsIPv4Private 需自行实现,判断是否在 10/172.16/192.168 段
&& ua.Address.ToString() != "0.0.0.0")
.Select(ua => ua.Address)
.FirstOrDefault();
-
OperationalStatus.Up是硬门槛,跳过“已启用但没连网线”或“WiFi 已关闭”的接口 - 只认
Ethernet和Wireless80211,避开Loopback、Tunnel、Ppp等干扰项 -
UnicastAddresses比AddressList更准确,它来自网卡实时配置,不是 DNS 缓存 - 务必检查
ua.Address.ToString() != "0.0.0.0"—— DHCP 获取中时地址就是 0.0.0.0,直接用会出错
怎么安全地获取本机 MAC 地址?
MAC 地址不能靠 DNS 或 IP 层 API 拿,必须走网卡驱动层。推荐用 NetworkInterface 类,但要注意过滤空值和无效类型:
var adapter = NetworkInterface.GetAllNetworkInterfaces()
.FirstOrDefault(nic =>
nic.OperationalStatus == OperationalStatus.Up &&
(nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211) &&
!string.IsNullOrEmpty(nic.GetPhysicalAddress().ToString()) &&
!nic.GetPhysicalAddress().ToString().Equals("000000000000", StringComparison.OrdinalIgnoreCase));
- 优先选
OperationalStatus.Up,而不是GetIsNetworkAvailable()—— 后者只告诉你“有没有网络”,不告诉你哪块卡在用 - 排除
"000000000000":某些虚拟网卡(如 Hyper-V 默认交换机)或禁用网卡会返回全零 MAC - 格式统一用
.Replace("-", "")或.Replace(":", "")清理分隔符,避免后续比对失败 - WMI 方式(
Win32_NetworkAdapter)虽可得更多字段,但在 Docker 容器、WSL 或权限受限环境容易抛ManagementException,非诊断场景不建议默认启用
Windows 上 GetAllNetworkInterfaces 返回空列表?
常见原因是系统禁用了“Network Connections”服务(对应服务名 Netman)。该服务负责向 .NET 暴露适配器元数据,一旦停止,GetAllNetworkInterfaces() 就拿不到任何真实网卡。
检查方法:运行 services.msc,找到 “Network Connections”,确认状态为“正在运行”。
另外,某些终端管控软件(如深信服 EDR、奇安信天擎)会在驱动层拦截 GetAdaptersAddresses 系统调用,此时即使服务开着,.NET 也可能返回空 —— 这类环境只能换 WMI 或 P/Invoke 绕行,但稳定性进一步下降。
真正麻烦的不是写不出代码,而是不同环境对“启用”“可用”“私有地址”的定义不一致。比如一台机器同时插着有线、连着 WiFi、还跑着 Docker,哪个 IP 才算“本机 IP”?业务上必须明确定义:是用于通信的出口地址?还是绑定设备的标识地址?否则再准的代码也救不了模糊的需求。


















