树莓派 4 网络管理器配置工具

目标是为Raspberry Pi 4编写一个Qt应用程序,可用于在不同的WLAN接入点之间切换并存储相关的凭据。 我使用了Raspbian-buster-lite图像和Qt安装,如 Raspberry Pi 4上的Qt 中所述作为起点。 此外,我还安装了NetworkManager,它可以通过shell命令(nmcli ...)使用。创建、配置和管理网络连接。 有关这方面的信息可以在 https://wiki.debian.org/de/NetworkManagerhttps://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:>