应枚举所有网卡并逐层筛选:先过滤 operationalstatus.up 且非 loopback/tunnel/ppp/unknown 类型,再提取非空硬件地址的 ethernet 或 wireless80211 网卡,最后获取符合 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 的 ipv4 单播地址。

要通过 NetworkInterface 正确获取系统中真实可用的物理网卡信息,不能靠猜网卡名(比如硬写 "eth0" 或 "en0"),也不能依赖主机名解析(如 Dns.GetHostName())。核心思路是:先枚举全部接口,再按运行状态、类型、地址特征逐层筛选。
遍历所有网卡并识别物理设备
调用 NetworkInterface.GetAllNetworkInterfaces()(C#)或 NetworkInterface.getNetworkInterfaces()(Java)拿到接口集合。每个接口对象包含名称(Name)、显示名(DisplayName)、运行状态、类型、硬件地址等关键字段。打印这些字段能快速看清系统实际识别到哪些网卡,比如 Windows 上可能看到“以太网”“WLAN”或带中文的“本地连接”,Linux 可能是 ens33、eno1,macOS 是 en0。
筛选启用的物理网卡
不是所有接口都符合“物理局域网网卡”的需求。需组合多个条件判断:
-
OperationalStatus == OperationalStatus.Up(C#)或isUp() == true(Java):确保网卡已启用且链路通 - 排除虚拟/逻辑类型:跳过
Loopback、Tunnel、Ppp、Unknown(C#);Java 中可结合getDisplayName()排除含 “VMware”、“Docker”、“vEthernet”、“WSL” 等关键字的接口 - 优先保留
Ethernet或Wireless80211(C#);Java 中虽无直接枚举类型,但可通过是否有非空getHardwareAddress()+ 非 loopback 判断物理性
提取有效的 IPv4 局域网地址
从筛选后的网卡中获取 IPv4 单播地址,并进一步验证是否为典型内网 IP:
- 地址族必须是
AddressFamily.InterNetwork(C#)或inetAddress.getAddress().length == 4(Java) - 排除回环(
127.0.0.0/8)、链路本地(169.254.0.0/16)、未分配(0.0.0.0)地址 - 只保留私有地址段:
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16—— 这才是你真正需要的局域网 IP - Java 中注意:Windows 下
getDisplayName()中文乱码时,可用new String(ni.getDisplayName().getBytes("ISO-8859-1"), "GBK")重解码
处理常见异常与限制
返回空列表或地址为 null 并不总代表代码错误:
- Linux/macOS 下 .NET Core/.NET 5+ 一般无需特殊权限,但 Docker 容器若未使用
--network host或未挂载/sys/class/net,会无法读取接口 - Windows 上若“Network Connections”服务被禁用,
GetAllNetworkInterfaces可能仅返回 loopback - Java 中
getHardwareAddress()返回 null,常见于权限不足(Linux 某些发行版需cap_net_raw)、SELinux 限制,或系统策略禁止暴露 MAC(如 Android、部分容器环境)










