目标是为Raspberry Pi 4编写一个Qt应用程序,可用于在不同的WLAN接入点之间切换并存储相关的凭据。 我使用了Raspbian-buster-lite图像和Qt安装,如 Raspberry Pi 4上的Qt 中所述作为起点。 此外,我还安装了NetworkManager,它可以通过shell命令(nmcli ...)使用。创建、配置和管理网络连接。 有关这方面的信息可以在 https://wiki.debian.org/de/NetworkManager 或 https://developer.gnome.org/NetworkManager/stable/nmcli.html 下找到。 NetworkManager 提供了一个可用于启动监控过程的命令,然后对各种接口(wlan0 或 eth0)的更改进行注释(例如不可用、断开连接、正在连接、已连接等)。 我想使用此监视在 GUI 中显示网络位置的不同状态。出现了2个问题:
- 如果快速连续发出多个 nmcli 命令,则有关不同状态的反馈会延迟到达,并且无法在 GUI 中实时显示。
- NMCLI 命令的反馈在不同的插槽中发送,因此可能协调不佳。
监控功能
首先,我们需要监控功能(monitorDevices)和公共时隙函数,例如,它拦截和评估监控输出,然后将状态消息发送到GUI。 在应用程序启动时自动启动的“monitorDevices”函数中,nmcli 命令使用 sudo 启动:sudo nmcli monitor 语句“setProcessChannelMode(QProcess::MergedChannels)”指出“标准输出”和“标准误差”一起显示在一个通道中,因此可以用函数进行评估。 每当显示消息(readyReadStandardOutput)时,都会使用“connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))”行,它被发送到插槽“processOutput”。
void CmdLauncher::monitorDevices() {
QStringList device_monitoring_on = {"nmcli", "monitor"};
device_monitoring_process = new QProcess(this);
device_monitoring_process->setProcessChannelMode(QProcess::MergedChannels);
device_monitoring_process->start("sudo", device_monitoring_on);
connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
}
</:code1:>
评估功能
然后在“processOutput”函数中对消息进行评估。QProcess senderProcess 截获所有 nmcli 命令的所有消息 - 而不仅仅是监视命令的消息。
void CmdLauncher::processOutput() {
QProcess* senderProcess = qobject_cast<QProcess*>(sender());
senderProcess->setReadChannel(QProcess::StandardOutput);
QString message = QString::fromLocal8Bit(senderProcess->readAllStandardOutput());
qDebug() << "CmdLauncher::processOutput message: " << message << endl;
if (message.contains("Error:")) {
message.remove(QString("\n"));
error_messages = message;
emit getErrorMessagesChanged();
if (message.contains(QString("Error: unknown connection"))) {
secrets_required = true;
emit getSecretsRequiredChanged();
}
}
// wifi
if (message.contains("wlan0: connected") || message.contains("wlan0:connected")) {
wifi_device_state = "Wifi-Connected";
emit getWifiDeviceStateChanged();
error_messages = "";
emit getErrorMessagesChanged();
rescanWifi();
testInternetConnection();
}
}
</:code2:>
启动另一个 nmcli 进程
如果您现在使用以下函数启动另一个 nmcli 命令,则输出将被上述监视函数截获,然后可以在 “outputProcess” 中进行评估和进一步处理。 此函数切换到现有网络连接并启动它。重要的是不要包含“set_wifi_process->waitForReadyRead()”或“set_wifi_process->waitForDone()”,因为这样所有消息的输出将被阻止,直到此过程完成。
void CmdLauncher::setWifi(QString ssid) {
error_messages = "";
emit getErrorMessagesChanged();
QString uuid = "";
for (int i = 0 ; i networkConnections.length() ; i++) {
QStringList connections = networkConnections[i].split(":");
if (connections[1] == ssid)
{
uuid = connections[2];
}
}
QStringList args_wifi_exist = {"nmcli", "connection", "up", uuid};
set_wifi_process = new QProcess(this);
set_wifi_process->setProcessChannelMode(QProcess::MergedChannels);
set_wifi_process->start("sudo", args_wifi_exist);
connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
}
行 “connect(set_wifi_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))” 将此过程的输出消息转发回 “processOutput”,并可以在中心位置再次评估。 </:code3:>