一、引言:为什么需要网络状态检测?
1.1 典型应用场景
在物联网和智能设备开发中,网络状态检测是基础而关键的功能。想象以下场景:
- 智能家居:当家庭wifi断开时,智能音箱自动开启热点模式,让用户通过手机直连配置
- 工业设备:生产线设备在检测到网络异常时,自动记录状态并开启维护通道
- 移动终端:平板电脑在不同网络环境下自动调整同步策略,节省电量
1.2 技术实现目标
实现以下核心功能:
功能 | 描述 | 技术指标 |
---|---|---|
wifi连接检测 | 判断设备是否连接到无线网络 | 响应时间<1s |
wifi名称获取 | 获取当前连接的无线网络ssid | 支持特殊字符 |
热点状态检测 | 判断设备是否处于热点模式 | 准确率100% |
热点名称获取 | 获取设备热点的ssid | 多编码支持 |
1.3 技术原理概述
linux系统通过networkmanager服务管理网络连接,提供了丰富的命令行工具:
- iwgetid:查询无线接口连接状态
- nmcli:networkmanager的命令行接口
- hostapd:热点管理服务
qt的qprocess
类可以无缝调用这些系统命令,并通过解析输出来获取网络状态信息。
二、核心思路:结合qt与linux命令
2.1 技术架构设计
2.2 关键命令分析
检测wifi连接状态
# 返回当前连接的ssid(无连接则返回空) iwgetid -r # 示例输出: # myhomewifi
检测热点状态
# 查看活动连接中的热点 nmcli connection show --active | grep wifi | grep ap # 查看hostapd进程 pgrep hostapd
获取热点名称
# 通过nmcli获取 nmcli device wifi show | grep ssid # 通过hostapd配置获取 grep ssid= /etc/hostapd/hostapd.conf
2.3 性能考量
- 命令执行时间:各命令在树莓派4上的平均执行时间
iwgetid
:50-100msnmcli
:200-300mspgrep
:10-20ms
- 优化策略:
- 缓存结果,减少命令调用
- 异步执行,避免阻塞ui
- 合理设置检测间隔(建议1-5秒)
三、详细实现:
3.1 核心类实现
networktool.h
#ifndef networktool_h #define networktool_h #include <qobject> #include <qprocess> #include <qtimer> class networktool : public qobject { q_object public: explicit networktool(qobject *parent = nullptr); // 基础检测功能 q_invokable bool iswificonnected(); q_invokable qstring wifiname(); q_invokable bool ishotspotactive(); q_invokable qstring hotspotname(); // 高级功能 q_invokable void startautorefresh(int interval = 3000); q_invokable void stopautorefresh(); signals: void wifistatuschanged(bool connected, const qstring &name); void hotspotstatuschanged(bool active, const qstring &name); private slots: void refreshstatus(); private: qstring executecommand(const qstring &cmd, const qstringlist &args = {}); qstring parsewifiname(const qstring &output); qstring parsehotspotname(const qstring &output); qtimer m_refreshtimer; bool m_lastwifistate = false; qstring m_lastwifiname; bool m_lasthotspotstate = false; qstring m_lasthotspotname; }; #endif // networktool_h
networktool.cpp
#include "networktool.h" #include <qdebug> #include <qfile> networktool::networktool(qobject *parent) : qobject(parent) { m_refreshtimer.setsingleshot(false); connect(&m_refreshtimer, &qtimer::timeout, this, &networktool::refreshstatus); } bool networktool::iswificonnected() { return !wifiname().isempty(); } qstring networktool::wifiname() { qstring output = executecommand("iwgetid", {"-r"}); return parsewifiname(output); } bool networktool::ishotspotactive() { // 方法1:使用nmcli检测 qstring output = executecommand("nmcli", {"connection", "show", "--active"}); if (output.contains("wifi") && output.contains("ap")) { return true; } // 方法2:检测hostapd进程 output = executecommand("pgrep", {"hostapd"}); return !output.isempty(); } qstring networktool::hotspotname() { // 尝试通过nmcli获取 qstring output = executecommand("nmcli", {"device", "wifi", "show"}); qstring name = parsehotspotname(output); if (!name.isempty()) return name; // 回退到读取hostapd配置 qfile config("/etc/hostapd/hostapd.conf"); if (config.open(qiodevice::readonly)) { while (!config.atend()) { qbytearray line = config.readline().trimmed(); if (line.startswith("ssid=")) { return qstring::fromutf8(line.mid(5)); } } } return "unknown"; } void networktool::startautorefresh(int interval) { m_refreshtimer.start(interval); } void networktool::stopautorefresh() { m_refreshtimer.stop(); } void networktool::refreshstatus() { // 获取当前状态 bool wificonnected = iswificonnected(); qstring currentwifiname = wifiname(); bool hotspotactive = ishotspotactive(); qstring currenthotspotname = hotspotname(); // 检查状态变化 if (wificonnected != m_lastwifistate || currentwifiname != m_lastwifiname) { m_lastwifistate = wificonnected; m_lastwifiname = currentwifiname; emit wifistatuschanged(wificonnected, currentwifiname); } if (hotspotactive != m_lasthotspotstate || currenthotspotname != m_lasthotspotname) { m_lasthotspotstate = hotspotactive; m_lasthotspotname = currenthotspotname; emit hotspotstatuschanged(hotspotactive, currenthotspotname); } } qstring networktool::executecommand(const qstring &cmd, const qstringlist &args) { qprocess process; process.start(cmd, args); if (!process.waitforfinished(1000)) { qwarning() << "command timeout:" << cmd << args; return ""; } return qstring::fromutf8(process.readallstandardoutput()).trimmed(); } qstring networktool::parsewifiname(const qstring &output) { // iwgetid -r 直接返回ssid或空 return output; } qstring networktool::parsehotspotname(const qstring &output) { // 解析nmcli输出中的ssid qstringlist lines = output.split('\n'); for (const qstring &line : lines) { if (line.trimmed().startswith("ssid:")) { return line.mid(5).trimmed(); } } return ""; }
3.2 ui集成示例
qt widgets版本
// mainwindow.h #include <qmainwindow> #include "networktool.h" namespace ui { class mainwindow; } class mainwindow : public qmainwindow { q_object public: explicit mainwindow(qwidget *parent = nullptr); ~mainwindow(); private slots: void onwifistatuschanged(bool connected, const qstring &name); void onhotspotstatuschanged(bool active, const qstring &name); private: ui::mainwindow *ui; networktool m_networktool; }; // mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" mainwindow::mainwindow(qwidget *parent) : qmainwindow(parent), ui(new ui::mainwindow) { ui->setupui(this); // 连接信号 connect(&m_networktool, &networktool::wifistatuschanged, this, &mainwindow::onwifistatuschanged); connect(&m_networktool, &networktool::hotspotstatuschanged, this, &mainwindow::onhotspotstatuschanged); // 启动自动刷新 m_networktool.startautorefresh(); // 初始化状态 onwifistatuschanged(m_networktool.iswificonnected(), m_networktool.wifiname()); onhotspotstatuschanged(m_networktool.ishotspotactive(), m_networktool.hotspotname()); } void mainwindow::onwifistatuschanged(bool connected, const qstring &name) { ui->wifistatuslabel->settext(connected ? "已连接" : "未连接"); ui->wifinamelabel->settext(connected ? name : "n/a"); ui->wifiicon->setpixmap(qpixmap(connected ? ":/icons/wifi-on.png" : ":/icons/wifi-off.png")); } void mainwindow::onhotspotstatuschanged(bool active, const qstring &name) { ui->hotspotstatuslabel->settext(active ? "已开启" : "未开启"); ui->hotspotnamelabel->settext(active ? name : "n/a"); ui->hotspoticon->setpixmap(qpixmap(active ? ":/icons/hotspot-on.png" : ":/icons/hotspot-off.png")); }
qml版本
// main.qml import qtquick 2.15 import qtquick.controls 2.15 import qtquick.layouts 1.15 applicationwindow { id: window width: 400 height: 300 visible: true title: "网络状态监测" networktool { id: networktool onwifistatuschanged: { wifistatustext.text = connected ? "已连接" : "未连接" wifinametext.text = name || "n/a" } onhotspotstatuschanged: { hotspotstatustext.text = active ? "已开启" : "未开启" hotspotnametext.text = name || "n/a" } component.oncompleted: startautorefresh() } columnlayout { anchors.fill: parent anchors.margins: 20 spacing: 15 groupbox { title: "wifi状态" layout.fillwidth: true gridlayout { columns: 2 width: parent.width label { text: "状态:" } label { id: wifistatustext } label { text: "名称:" } label { id: wifinametext } } } groupbox { title: "热点状态" layout.fillwidth: true gridlayout { columns: 2 width: parent.width label { text: "状态:" } label { id: hotspotstatustext } label { text: "名称:" } label { id: hotspotnametext } } } button { text: "手动刷新" layout.alignment: qt.alignhcenter onclicked: networktool.refreshstatus() } } }
四、注意事项:避坑指南
4.1 权限问题解决
常见权限错误:
nmcli
报错:“权限不足”iwgetid
无法获取信息
解决方案:
polkit规则配置(推荐):
sudo nano /etc/polkit-1/rules.d/10-network-info.rules
添加内容:
polkit.addrule(function(action, subject) { if (action.id.indexof("org.freedesktop.networkmanager.") == 0 && subject.isingroup("users")) { return polkit.result.yes; } });
用户组配置:
sudo usermod -ag netdev,network $user
sudo免密码(开发测试用):
echo "$user all=(all) nopasswd: /usr/bin/nmcli, /usr/bin/iwgetid" | sudo tee /etc/sudoers.d/network
4.2 系统兼容性处理
不同发行版适配:
发行版 | 检测命令 | 配置文件路径 |
---|---|---|
ubuntu/debian | nmcli/iwgetid | /etc/networkmanager/ |
centos/rhel | nmcli/iw | /etc/sysconfig/network-scripts/ |
arch linux | iw/wpa_cli | /etc/netctl/ |
兼容性代码改进:
qstring networktool::wifiname() { // 尝试iwgetid qstring output = executecommand("iwgetid", {"-r"}); if (!output.isempty()) return output; // 回退到iw命令 output = executecommand("iw", {"dev", "wlan0", "link"}); qregularexpression regex("ssid: (.+)"); qregularexpressionmatch match = regex.match(output); if (match.hasmatch()) { return match.captured(1); } return ""; }
4.3 性能优化进阶
优化策略:
- 命令执行优化:
// 异步执行命令 void networktool::executecommandasync( const qstring &cmd, const qstringlist &args, std::function<void(qstring)> callback) { qprocess *process = new qprocess(this); connect(process, qoverload<int, qprocess::exitstatus>::of(&qprocess::finished), [=](int exitcode, qprocess::exitstatus exitstatus){ if (exitstatus == qprocess::normalexit) { callback(qstring::fromutf8(process->readallstandardoutput())); } process->deletelater(); }); process->start(cmd, args); }
- 智能刷新机制:
void networktool::refreshstatus() { // 仅当界面可见时刷新 if (!m_windowvisible) return; // 根据网络状态动态调整间隔 if (m_lastwifistate) { m_refreshtimer.setinterval(5000); // 连接状态稳定时降低频率 } else { m_refreshtimer.setinterval(1000); // 未连接时提高检测频率 } // ...原有刷新逻辑... }
- 结果缓存:
struct networkcache { bool wificonnected; qstring wifiname; bool hotspotactive; qstring hotspotname; qdatetime lastupdated; }; networkcache m_cache; void networktool::refreshcache() { if (m_cache.lastupdated.secsto(qdatetime::currentdatetime()) < 2) { return; // 2秒内不重复更新 } // ...更新缓存... }
五、扩展
智能网络切换:
void autoswitchnetwork() { if (!m_networktool.iswificonnected() && !m_networktool.ishotspotactive()) { // wifi断开且热点未开启时,自动开启热点 qprocess::startdetached("nmcli", { "device", "wifi", "hotspot", "ssid", "rescuehotspot", "password", "12345678" }); } }
网络质量监测:
int getwifisignalstrength() { qstring output = executecommand("iwconfig", {"wlan0"}); qregularexpression regex("signal level=(-?\\d+) dbm"); qregularexpressionmatch match = regex.match(output); if (match.hasmatch()) { return match.captured(1).toint(); } return 0; }
历史状态记录:
void lognetworkstatus() { qfile logfile("network_status.log"); if (logfile.open(qiodevice::append)) { qstring log = qstring("%1|%2|%3|%4\n") .arg(qdatetime::currentdatetime().tostring()) .arg(m_lastwifistate) .arg(m_lastwifiname) .arg(m_lasthotspotstate); logfile.write(log.toutf8()); } }
以上就是linux下实时获取wifi与热点状态的方法详解的详细内容,更多关于linux获取wifi与热点状态的资料请关注代码网其它相关文章!
发表评论