一、引言:为什么需要网络状态检测?
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与热点状态的资料请关注代码网其它相关文章!
发表评论