动态计算本机局域网网段需筛选OperationalStatus.Up且类型为Ethernet/Wireless80211的接口,对IPv4地址与子网掩码按位与运算得网络地址,排除APIPA、回环、广播及虚拟网卡IP;Ping并发须用SemaphoreSlim限速(4–8)、单次超时200ms、禁复用Ping实例;Ping成功后调SendARP查MAC,失败则可能ICMP屏蔽而ARP仍通。

直接用 Ping.SendPingAsync 遍历整个私有地址段(比如 192.168.0.0/16)在实际项目中基本不可行——不是代码写不对,而是 Windows 网络栈和防火墙策略天然限制了这种粗暴扫描的可用性。真正能落地的方案,是「先算准本机网段 + 并发控速 + Ping 后补 ARP」三步闭环。
怎么动态算出本机真实局域网网段?
硬写 "192.168.1.0/24" 是最大误区。用户可能连着 WiFi、有线、Hyper-V 虚拟交换机,甚至 WSL2 的 vEthernet,NetworkInterface.GetAllNetworkInterfaces() 返回的适配器里混着七八个 IPv4 地址。
- 必须筛选
OperationalStatus.Up且NetworkInterfaceType.Ethernet或Wireless80211的接口 - 对每个接口的
UnicastAddresses取 IPv4 地址,再用子网掩码做位运算算网络地址(别手动画减法,IPAddress.NetworkToHostOrder+ 按位与更稳) - 跳过
169.254.x.x(APIPA)、127.x.x.x、0.0.0.0和广播地址(如192.168.1.255) - 虚拟网卡名称含
"vEthernet"、"WSL"、"Docker"的,按需排除——它们的 IP 不代表物理局域网可达性
为什么 Ping.SendPingAsync 批量调用会崩?
不是 API 有 bug,是并发失控+超时缺位导致系统级拒绝服务:瞬间几百个 ICMP 请求触发连接数上限,多数返回 IPStatus.TimedOut 或直接抛 InvalidOperationException。
- 必须用
SemaphoreSlim控制并发,4–8 是实测安全阈值 - 每个
Ping实例设timeout = 200(毫秒),局域网内够用;设太长(如 1000ms)会导致整体耗时爆炸 - 绝不能复用同一个
Ping对象——它非线程安全,多线程调用必出错 - 跳过已知无效地址:
127.0.0.1、0.0.0.0、广播地址、全零地址
收到 Ping 响应后,怎么顺手拿到 MAC 地址?
只记录 IP 没意义,MAC 才是定位设备的关键。Windows 下靠 SendARP API,但它不发新请求,只查本地 ARP 缓存。
- 先
await ping.SendPingAsync(ip, 200),成功后再调SendARP查 MAC -
SendARP失败返回65(ERROR_INVALID_PARAMETER)很常见——说明目标没响应 ARP,或跨 VLAN、开了防火墙但没关 ARP - 如果
Ping失败但SendARP成功,大概率是 ICMP 被屏蔽、ARP 仍通,这类设备要单独标记 - 需要
[DllImport("iphlpapi.dll")]引入,输出 MAC 是uint[6]数组,转字节再格式化为"XX-XX-XX-XX-XX-XX"
真正的难点不在代码怎么写,而在「网段识别是否覆盖所有启用的物理接口」和「ARP 缓存是否被主动刷新过」——这两点不处理,扫描结果永远漏设备或误判离线。


















