最可靠方式是Windows用GetIpNetTable2、Linux用/proc/net/arp;需按协议族传参、过滤无效状态、解析IP/MAC、运行时探测路径而非预编译宏,arp-a仅作保底且须正则提取。

Windows 下用 GetIpNetTable2 读取 ARP 缓存最可靠
直接调用系统 API 比解析 arp -a 命令输出稳定得多,不会受语言 locale、格式换行、表头变化影响。Win10+ 推荐用 GetIpNetTable2(支持 IPv4/IPv6),旧系统可用 GetIpNetTable,但后者不返回接口索引,多网卡时容易混淆。
关键点:
-
GetIpNetTable2需传入AF_INET或AF_INET6指定协议族,返回的是MIB_IPNET_ROW2*数组,每项含State(如Reachable、Stale)、InterfaceIndex、IpAddress和PhysicalAddress - 调用前必须用
ConvertStringToAddressA或inet_pton解析 IP 字符串;MAC 地址是 6 字节数组,需手动转为XX-XX-XX-XX-XX-XX格式 - 返回的表可能包含
Invalid或Incomplete条目,建议过滤掉State != IpNetRowState::Reachable && State != IpNetRowState::Stale
Linux 下用 /proc/net/arp 是最轻量方案
不用链接 libnetfilter 或调用 ip neigh,直接读文件即可,兼容所有内核版本(2.6+)。路径固定为 /proc/net/arp,每行字段顺序为:IP_address HW_type Flags HW_address Masks Device。
注意细节:
- 第 4 列
HW_address是 MAC,格式为xx:xx:xx:xx:xx:xx,但某些嵌入式系统可能用点分十六进制(如0011.2233.4455),需正则适配 - 第 3 列
Flags是十六进制数,0x2表示COMPLETE(有效映射),0x4是PERMANENT(静态条目),0x8是NOARP(禁用 ARP)——只取Flags & 0x2非零的行 - 首行是表头,必须跳过;空行或注释行(# 开头)也要忽略
跨平台封装时别硬写 ifdefs,优先用运行时探测
预编译宏(如 #ifdef _WIN32)会让代码难以测试,尤其在 WSL 环境下 Linux 代码可能被误编译。更稳妥的做法是:启动时检查 /proc/net/arp 是否可读,能读就走 Linux 路径;否则尝试调用 GetIpNetTable2,失败再 fallback 到 arp -a 解析(仅作保底)。
这样做的好处:
- WSL1/WSL2 自动走 Linux 分支,无需额外配置
- Windows Server Core 容器里若没装 PowerShell,
arp -a仍可用,但 API 调用更高效 - 避免因头文件缺失(如
iphlpapi.h未 link)导致链接失败,错误更早暴露
arp -a 解析要防住三类典型坏数据
当 API 不可用或需快速验证时,调用命令行仍是兜底手段,但输出极不稳定:
- 中文 Windows 会把 “Internet Address” 显示为 “互联网地址”,列宽不固定,不能靠空格切分——必须用正则匹配 IP(
\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b)和 MAC(\b(?:[0-9A-Fa-f]{2}-){5}[0-9A-Fa-f]{2}\b) - 某些设备(如打印机)ARP 条目 MAC 全为
00-00-00-00-00-00,这类应丢弃,否则污染结果 -
Interface: 192.168.1.100这样的行不是数据行,是网卡分隔符,需识别并记录当前接口,后续条目才知归属
真实环境中,GetIpNetTable2 返回的 InterfaceIndex 和 /proc/net/arp 的最后一列 Device 才是定位物理网卡的唯一依据,仅靠 IP 段推测(比如“192.168.x.x 就是 wlan0”)在复杂网络中必然出错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











