Windows平台最可靠的方式是调用GetAdaptersAddresses,需链接Iphlpapi.lib、传AF_UNSPEC获取双栈信息、两次调用处理缓冲区(先NULL获大小再分配重试)、遍历链表检查PhysicalAddressLength提取MAC,并用FreeAdaptersAddresses释放内存。

Windows平台用GetAdaptersAddresses获取适配器列表
Windows下最可靠的方式是调用GetAdaptersAddresses,它能返回包括IPv4/IPv6地址、MAC、状态、描述、DNS服务器等完整信息。注意必须链接Iphlpapi.lib,且需用AF_UNSPEC作为地址族参数才能同时获取双栈信息。
常见错误是传AF_INET只查IPv4,结果漏掉IPv6地址或某些虚拟网卡(如WSL2的vEthernet)。另外返回缓冲区大小不足时函数会返回ERROR_BUFFER_OVERFLOW,必须按提示重分配内存再调用——不能直接忽略。
- 调用前先传
NULL和0获取所需缓冲区大小 - 分配足够内存后第二次调用,检查返回值是否为
NO_ERROR -
Adapter->FirstUnicastAddress链表里每个IP_ADAPTER_UNICAST_ADDRESS对应一个IP地址,需遍历解析Address.lpSockaddr - MAC地址在
Adapter->PhysicalAddress中,长度由Adapter->PhysicalAddressLength给出
Linux下读取/sys/class/net和getifaddrs混合使用
Linux没有统一API,稳妥做法是:用getifaddrs获取IP地址和家族信息,再从/sys/class/net/<iface>/读取MAC、状态、速度等元数据。纯getifaddrs拿不到MTU、操作状态(up/down)、驱动名这些字段。
容易踩的坑是getifaddrs返回的ifa_addr可能为NULL(比如lo接口未配置IPv4),需判空;另外AF_PACKET类型的地址才含MAC,但部分内核版本(尤其容器环境)可能不暴露,此时必须fallback到/sys/class/net/<iface>/address。
立即学习“C++免费学习笔记(深入)”;
- 遍历
getifaddrs结果时,用ifa->ifa_addr->sa_family区分AF_INET/AF_INET6/AF_PACKET - 读
/sys/class/net/<iface>/operstate判断是否up,/sys/class/net/<iface>/mtu读MTU值 - 注意
/sys/class/net/下软链接(如bonding子接口)需用readlink解析真实路径 - 容器内可能挂载了
sysfs但权限受限,open()失败时应降级处理而非崩溃
跨平台封装要注意的三类差异
Windows和Linux对“适配器”的定义不同:Windows把隧道、回环、NDIS中间层都算作独立适配器;Linux通常只暴露/sys/class/net/下的条目,且docker/bridge接口需额外过滤。统一抽象时最容易出错的是状态映射和名称一致性。
比如Windows的Adapter->Description含Unicode,而Linux的ifa_name是ASCII;Windows用OperStatus枚举值(1=Up, 2=Down),Linux得靠operstate文件内容字符串匹配。还有MTU:Windows从Adapter->Mtu取,Linux必须读文件,且某些虚拟设备(如veth)的MTU字段可能不可写。
- 名称字段优先用
Adapter->FriendlyName(Win)或ifa_name(Linux),避免用描述性字段做唯一标识 - 状态判断不要硬编码字符串比较,Linux侧统一转小写再比
"up"/"down" - MAC地址格式:Windows是字节数组,Linux sysfs里是冒号分隔十六进制字符串,解析时别直接
sscanf整个串 - IPv6地址作用域(scope)信息Linux可通过
ifa->ifa_flags & IFA_F_SECONDARY等标志推断,Windows需查Adapter->Ipv6IfIndex配合ConvertInterfaceIndexToLuid
性能与内存安全关键点
GetAdaptersAddresses在Windows上可能耗时几十毫秒(尤其有大量虚拟网卡时),而getifaddrs在Linux上是纯用户态链表遍历,快得多。但两者都要求显式释放内存:FreeAdaptersAddresses或freeifaddrs,漏掉就会泄漏。
更隐蔽的问题是并发:如果在多线程环境中反复调用,Windows版若共用同一缓冲区指针可能被覆盖;Linux版getifaddrs返回的内存块是malloc分配的,但内部指针(如ifa_addr)指向该块内偏移,不能单独free某子结构。
- Windows侧每次调用前必须重分配缓冲区,别复用上次的指针
- Linux侧拿到
ifaddrs*后尽快处理完再调freeifaddrs,别保存ifa_addr指针长期使用 - 调试时可用
Valgrind(Linux)或Application Verifier(Windows)捕获未释放问题 - 生产环境建议加超时:Windows调用可设
SetThreadExecutionState防休眠,Linux可alarm()兜底
ScopeId和Linux下veth接口的“无MAC”现象——它们在getifaddrs里不返回AF_PACKET地址,必须走sysfs补全。


















