用Ping.SendPingAsync扫描局域网需控制并发(SemaphoreSlim限4–8)、单次超时200ms、不复用Ping实例,并动态计算本机网段;MAC地址通过SendARP获取,依赖ARP缓存,失败提示设备可能存在但ICMP被屏蔽。

用 UdpClient 发 ICMP 探测不现实,别试了
Windows 默认禁用非管理员进程发原始 ICMP 包,UdpClient 本身也不支持 ping;强行用 System.Net.NetworkInformation.Ping 遍历网段虽可行,但超时设置难控、并发差、容易卡死主线程。这不是 API 用得不对,是设计上就不适合扫网段。
Ping.SendPingAsync 批量探测要加超时和并发限制
直接 for 循环调用 Ping.SendPingAsync 不设限,会瞬间发几百个请求,多数返回 TimedOut 或抛 InvalidOperationException(连接数超限)。必须控制节奏:
- 用
SemaphoreSlim限制并发数,4–8 比较稳妥 - 每个
Ping实例设Timeout = 200毫秒,局域网够用 - 别复用同一个
Ping对象——它不是线程安全的 - 跳过
127.0.0.1、0.0.0.0、广播地址(如192.168.1.255)
示例关键片段:
var ping = new Ping();
var reply = await ping.SendPingAsync(ip, 200); // 注意 timeout 是毫秒
if (reply.Status == IPStatus.Success) { /* 记录在线 */ }
先获取本机局域网网段,别硬写 192.168.1.0/24
用户可能连着 WiFi、有线、虚拟网卡,甚至多网卡并存。靠猜网段会漏设备或扫错范围:
- 用
NetworkInterface.GetNetworkInterfaces()筛选OperationalStatus.Up且NetworkInterfaceType.Ethernet或Wireless80211 - 遍历
UnicastAddresses,找 IPv4 地址 + 子网掩码,算出网络地址(比如192.168.1.100/255.255.255.0 → 192.168.1.0) - 排除
169.254.x.x(APIPA)和127.x.x.x
算网段别手动画,用 IPAddress.NetworkToHostOrder 和位运算更稳,不然掩码为 255.255.0.0 时容易算错边界。
收到响应后别只看 IP,顺手抓下 MAC 地址更实用
单纯知道 IP 在线意义有限,局域网定位设备常需 MAC。Windows 下可用 SendARP 原生 API 补全:
- 引用
System.Runtime.InteropServices - 调
SendARP传入目标 IP 和本机 IP,输出uint数组存 MAC(6 字节) - 失败时返回
65(ERROR_INVALID_PARAMETER)很常见——说明目标没响应 ARP,或跨 VLAN - 注意:该 API 不触发主动 ARP 请求,依赖本地 ARP 缓存命中;首次扫描可先
Ping一下再查
MAC 获取失败比 Ping 失败更值得记录——它暗示设备存在但隔离了 ICMP,或开了防火墙但没关 ARP。
实际跑起来会发现:快不是关键,稳才是。一个子网扫下来 3–5 秒正常,想压到 1 秒内,丢包率就不可控。重点不在“怎么扫全”,而在“怎么不扫崩自己”。









