Linux下實(shí)時(shí)獲取WiFi與熱點(diǎn)狀態(tài)的方法詳解
一、引言:為什么需要網(wǎng)絡(luò)狀態(tài)檢測(cè)?
1.1 典型應(yīng)用場(chǎng)景
在物聯(lián)網(wǎng)和智能設(shè)備開發(fā)中,網(wǎng)絡(luò)狀態(tài)檢測(cè)是基礎(chǔ)而關(guān)鍵的功能。想象以下場(chǎng)景:
- 智能家居:當(dāng)家庭WiFi斷開時(shí),智能音箱自動(dòng)開啟熱點(diǎn)模式,讓用戶通過手機(jī)直連配置
- 工業(yè)設(shè)備:生產(chǎn)線設(shè)備在檢測(cè)到網(wǎng)絡(luò)異常時(shí),自動(dòng)記錄狀態(tài)并開啟維護(hù)通道
- 移動(dòng)終端:平板電腦在不同網(wǎng)絡(luò)環(huán)境下自動(dòng)調(diào)整同步策略,節(jié)省電量
1.2 技術(shù)實(shí)現(xiàn)目標(biāo)
實(shí)現(xiàn)以下核心功能:
| 功能 | 描述 | 技術(shù)指標(biāo) |
|---|---|---|
| WiFi連接檢測(cè) | 判斷設(shè)備是否連接到無線網(wǎng)絡(luò) | 響應(yīng)時(shí)間<1s |
| WiFi名稱獲取 | 獲取當(dāng)前連接的無線網(wǎng)絡(luò)SSID | 支持特殊字符 |
| 熱點(diǎn)狀態(tài)檢測(cè) | 判斷設(shè)備是否處于熱點(diǎn)模式 | 準(zhǔn)確率100% |
| 熱點(diǎn)名稱獲取 | 獲取設(shè)備熱點(diǎn)的SSID | 多編碼支持 |
1.3 技術(shù)原理概述
Linux系統(tǒng)通過NetworkManager服務(wù)管理網(wǎng)絡(luò)連接,提供了豐富的命令行工具:
- iwgetid:查詢無線接口連接狀態(tài)
- nmcli:NetworkManager的命令行接口
- hostapd:熱點(diǎn)管理服務(wù)
Qt的QProcess類可以無縫調(diào)用這些系統(tǒng)命令,并通過解析輸出來獲取網(wǎng)絡(luò)狀態(tài)信息。
二、核心思路:結(jié)合Qt與Linux命令
2.1 技術(shù)架構(gòu)設(shè)計(jì)

2.2 關(guān)鍵命令分析
檢測(cè)WiFi連接狀態(tài)
# 返回當(dāng)前連接的SSID(無連接則返回空) iwgetid -r # 示例輸出: # MyHomeWiFi
檢測(cè)熱點(diǎn)狀態(tài)
# 查看活動(dòng)連接中的熱點(diǎn) nmcli connection show --active | grep wifi | grep ap # 查看hostapd進(jìn)程 pgrep hostapd
獲取熱點(diǎn)名稱
# 通過nmcli獲取 nmcli device wifi show | grep SSID # 通過hostapd配置獲取 grep ssid= /etc/hostapd/hostapd.conf
2.3 性能考量
- 命令執(zhí)行時(shí)間:各命令在樹莓派4上的平均執(zhí)行時(shí)間
iwgetid:50-100msnmcli:200-300mspgrep:10-20ms
- 優(yōu)化策略:
- 緩存結(jié)果,減少命令調(diào)用
- 異步執(zhí)行,避免阻塞UI
- 合理設(shè)置檢測(cè)間隔(建議1-5秒)
三、詳細(xì)實(shí)現(xiàn):
3.1 核心類實(shí)現(xiàn)
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);
// 基礎(chǔ)檢測(cè)功能
Q_INVOKABLE bool isWifiConnected();
Q_INVOKABLE QString wifiName();
Q_INVOKABLE bool isHotspotActive();
Q_INVOKABLE QString hotspotName();
// 高級(jí)功能
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檢測(cè)
QString output = executeCommand("nmcli", {"connection", "show", "--active"});
if (output.contains("wifi") && output.contains("ap")) {
return true;
}
// 方法2:檢測(cè)hostapd進(jìn)程
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()
{
// 獲取當(dāng)前狀態(tài)
bool wifiConnected = isWifiConnected();
QString currentWifiName = wifiName();
bool hotspotActive = isHotspotActive();
QString currentHotspotName = hotspotName();
// 檢查狀態(tài)變化
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);
// 連接信號(hào)
connect(&m_networkTool, &NetworkTool::wifiStatusChanged,
this, &MainWindow::onWifiStatusChanged);
connect(&m_networkTool, &NetworkTool::hotspotStatusChanged,
this, &MainWindow::onHotspotStatusChanged);
// 啟動(dòng)自動(dòng)刷新
m_networkTool.startAutoRefresh();
// 初始化狀態(tài)
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: "網(wǎng)絡(luò)狀態(tài)監(jiān)測(cè)"
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狀態(tài)"
Layout.fillWidth: true
GridLayout {
columns: 2
width: parent.width
Label { text: "狀態(tài):" }
Label { id: wifiStatusText }
Label { text: "名稱:" }
Label { id: wifiNameText }
}
}
GroupBox {
title: "熱點(diǎn)狀態(tài)"
Layout.fillWidth: true
GridLayout {
columns: 2
width: parent.width
Label { text: "狀態(tài):" }
Label { id: hotspotStatusText }
Label { text: "名稱:" }
Label { id: hotspotNameText }
}
}
Button {
text: "手動(dòng)刷新"
Layout.alignment: Qt.AlignHCenter
onClicked: networkTool.refreshStatus()
}
}
}
四、注意事項(xiàng):避坑指南
4.1 權(quán)限問題解決
常見權(quán)限錯(cuò)誤:
nmcli報(bào)錯(cuò):“權(quán)限不足”iwgetid無法獲取信息
解決方案:
Polkit規(guī)則配置(推薦):
sudo nano /etc/polkit-1/rules.d/10-network-info.rules
添加內(nèi)容:
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免密碼(開發(fā)測(cè)試用):
echo "$USER ALL=(ALL) NOPASSWD: /usr/bin/nmcli, /usr/bin/iwgetid" | sudo tee /etc/sudoers.d/network
4.2 系統(tǒng)兼容性處理
不同發(fā)行版適配:
| 發(fā)行版 | 檢測(cè)命令 | 配置文件路徑 |
|---|---|---|
| Ubuntu/Debian | nmcli/iwgetid | /etc/NetworkManager/ |
| CentOS/RHEL | nmcli/iw | /etc/sysconfig/network-scripts/ |
| Arch Linux | iw/wpa_cli | /etc/netctl/ |
兼容性代碼改進(jìn):
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 性能優(yōu)化進(jìn)階
優(yōu)化策略:
- 命令執(zhí)行優(yōu)化:
// 異步執(zhí)行命令
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);
}
- 智能刷新機(jī)制:
void NetworkTool::refreshStatus()
{
// 僅當(dāng)界面可見時(shí)刷新
if (!m_windowVisible) return;
// 根據(jù)網(wǎng)絡(luò)狀態(tài)動(dòng)態(tài)調(diào)整間隔
if (m_lastWifiState) {
m_refreshTimer.setInterval(5000); // 連接狀態(tài)穩(wěn)定時(shí)降低頻率
} else {
m_refreshTimer.setInterval(1000); // 未連接時(shí)提高檢測(cè)頻率
}
// ...原有刷新邏輯...
}
- 結(jié)果緩存:
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秒內(nèi)不重復(fù)更新
}
// ...更新緩存...
}
五、擴(kuò)展
智能網(wǎng)絡(luò)切換:
void autoSwitchNetwork()
{
if (!m_networkTool.isWifiConnected() &&
!m_networkTool.isHotspotActive()) {
// WiFi斷開且熱點(diǎn)未開啟時(shí),自動(dòng)開啟熱點(diǎn)
QProcess::startDetached("nmcli", {
"device", "wifi", "hotspot",
"ssid", "RescueHotspot",
"password", "12345678"
});
}
}
網(wǎng)絡(luò)質(zhì)量監(jiān)測(cè):
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;
}
歷史狀態(tài)記錄:
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下實(shí)時(shí)獲取WiFi與熱點(diǎn)狀態(tài)的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Linux獲取WiFi與熱點(diǎn)狀態(tài)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Linux體檢,了解你的Linux狀態(tài)(網(wǎng)絡(luò)IO,磁盤,CPU,內(nèi)存)
這篇文章主要介紹了為L(zhǎng)inux做個(gè)檢查,了解你的Linux的狀態(tài),學(xué)會(huì)查看linux各種狀態(tài),包括:網(wǎng)絡(luò)IO、磁盤、CPU、內(nèi)存等; 學(xué)會(huì)理解命令所代表的含義,能夠迅速發(fā)現(xiàn)集群存在的問題2021-08-08
Ubuntu報(bào)“無法解析域名cn.archive.ubuntu.com“問題解決辦法
在Ubuntu系統(tǒng)上使用sudo?apt?update命令更新時(shí)可能遇到“無法解析域名cn.archive.ubuntu.com”的問題,這通常是因?yàn)閏n.archive.ubuntu.com的鏡像資源不穩(wěn)定,為解決此問題,可以更換為穩(wěn)定性好、速度快的鏡像源,需要的朋友可以參考下2024-11-11
Linux文件系統(tǒng)掛載參數(shù)優(yōu)化指南
在Linux系統(tǒng)管理與性能調(diào)優(yōu)的世界里,文件系統(tǒng)的掛載參數(shù)往往被忽視,卻對(duì)系統(tǒng)整體性能、穩(wěn)定性和安全性有著深遠(yuǎn)影響,本文將深入探討Linux主流文件系統(tǒng)(ext4, XFS, Btrfs等)的掛載參數(shù)優(yōu)化策略,需要的朋友可以參考下2026-04-04
Linux/Unix關(guān)于時(shí)間和時(shí)間戳的命令行
這篇文章主要介紹了Linux/Unix關(guān)于時(shí)間和時(shí)間戳的命令行以及輸出的樣式區(qū)別,一起來學(xué)習(xí)下吧。2017-12-12

