linux用iw/iwlist、windows用wlanqueryinterface、macos用airport/corewlan分别获取wifi信号强度与ssid,三者api差异大,需分平台实现,统一输出ssid、rssi_dbm、is_connected字段。

Linux 下用 iwlist 和 iw 获取无线信号强度与 SSID
Linux 没有统一的 C++ 系统 API 直接读取 WiFi 信号强度,最可靠的方式是调用命令行工具解析输出。其中 iwlist(老旧但兼容性好)和 iw(现代推荐)是核心工具。
注意:iwlist 需要 root 权限才能扫描,而 iw 在多数发行版中普通用户可执行 iw dev wlan0 link 查当前连接状态(含 signal: 值),但无法直接扫描未连接的 AP;若需扫描所有可见 SSID+信号,仍得用 iw dev wlan0 scan + iw event 或临时提权。
实操建议:
- 优先用
iw dev wlan0 link获取当前已连网络的SSID和signal(单位 dBm,负值越小信号越弱) - 若需列出周边所有 AP,用
iw dev wlan0 scan && iw dev wlan0 scan dump,注意扫描耗时约 2–5 秒,且部分驱动不支持无特权扫描 - 解析时别依赖固定列偏移——
iw输出是键值对格式,按行匹配SSID:、signal:、freq:更稳定 - C++ 中用
popen()调用并逐行读取,避免用system()丢失输出
Windows 下用 WlanQueryInterface 读取当前连接的信号强度
Windows 提供 WinAPI wlanapi.h,但仅能获取「当前已连接」无线接口的信号强度,不能扫描周围 AP。关键函数是 WlanQueryInterface,查询 wlan_intf_opcode_current_connection 后再查 wlan_intf_opcode_rssi。
常见错误现象:WlanOpenHandle 失败常因没链接 wlanapi.lib 或权限不足(UAC 提权非必需,但服务可能被禁用);WlanEnumInterfaces 返回空列表多因 WLAN AutoConfig 服务未运行。
实操建议:
- 必须先调用
WlanOpenHandle获取HANDLE,失败时检查GetLastError()是否为ERROR_SERVICE_NOT_ACTIVE -
WlanQueryInterface查询wlan_intf_opcode_rssi时,返回值是int类型的 dBm 值(如 -64),不是百分比 - SSID 从
wlan_intf_opcode_current_connection的WLAN_CONNECTION_ATTRIBUTES结构中取strProfileName字段(即连接时用的配置名),实际广播 SSID 在dot11Ssid.ucSSID中,但仅当已连上才有效 - 不要尝试用
WlanScan后立刻WlanGetNetworkBssList——中间需等几秒,否则返回空;且该流程不保证获取到信号强度字段,部分驱动填充不全
macOS 下靠 airport 命令 + CoreWLAN 混合使用
macOS 没开放底层射频接口给第三方程序,C++ 项目只能走两条路:调 /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport 命令,或用 Objective-C++ 混编调 CoreWLAN 框架。后者更健壮但增加构建复杂度。
使用场景差异明显:airport -I 只返回当前连接信息(含 agrCtlRSSI 字段,即信号强度),而 airport -s 扫描周边网络,输出含 SSID、RSSI、BSSID、信道等——但 RSSI 是估算值,非真实硬件测量。
实操建议:
-
airport -I输出中的agrCtlRSSI是主要参考值,范围通常 -30(极强)到 -90(极弱),注意它和 Linux 的signal:数值接近但算法不同 -
airport -s扫描结果里 RSSI 列实际是AGE(上次更新时间)或空,真 RSSI 在隐藏列;可靠做法是解析整行,用正则匹配类似SSID.*?(-\d+)的模式(因 macOS 版本间格式浮动大) - 若选
CoreWLAN,必须用objc_msgSend或桥接类,C++ 直接调会链接失败;且需在 Xcode 中启用 Objective-C++(.mm 后缀)并添加CoreWLAN.framework - 普通用户可执行
airport,无需 sudo,但路径必须写全,硬编码/usr/libexec/airport会失效(该路径仅符号链接,真实路径随系统版本变)
跨平台封装要注意的三个硬伤
没有“一次编写、到处读取 WiFi 信号”的 C++ 库。libnl(Linux)、WlanAPI(Windows)、CoreWLAN(macOS)三者抽象层差异极大,强行统一封装反而增加维护成本。
最容易被忽略的点:
- 信号强度单位不统一:Linux
iw和 Windows 都是 dBm,macOSagrCtlRSSI也是 dBm,但某些嵌入式驱动或旧网卡返回的是百分比(0–100),需查文档确认 - SSID 编码问题:Linux
iw输出默认 UTF-8,Windows API 返回宽字符(wchar_t*),macOSairport输出是 UTF-8,但 SSID 本身可能含不可见控制字符,打印前务必做isprint()过滤或转义 - 权限与竞态:Linux 扫描需 root,Windows 服务可能被组策略禁用,macOS 的
airport在 Catalina+ 默认禁止终端调用——需用户手动在“隐私→完全磁盘访问”中授权你的二进制文件
真正稳定的方案,是按平台分别实现最小可行调用,不追求代码复用,而追求各平台下输出字段语义一致(例如统一用 ssid、rssi_dbm、is_connected 三个字段返回)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











