Raspberry Pi 4 NetworkManager 구성 도구

목표는 서로 다른 WLAN 액세스 포인트 사이를 전환하고 관련 자격 증명을 저장하는 데 사용할 수 있는 Raspberry Pi 4용 Qt 애플리케이션을 작성하는 것이었습니다.
Raspberry Pi 4의 Qt 에 설명된 대로 raspbian-buster-lite 이미지와 Qt 설치를 시작점으로 사용했습니다.
또한 셸 명령 (nmcli ...)에서 사용할 수있는 NetworkManager를 설치했습니다. 네트워크 연결을 만들고, 구성하고, 관리합니다.
이에 대한 정보는 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)" 문은 "표준 출력"과 "표준 오류"가 채널에 함께 표시되므로 함수로 평가할 수 있음을 나타냅니다.
"connect(device_monitoring_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()))" 행은 메시지가 표시될 때마다(readyReadStandardOutput) 사용되며 "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->waitForFinished()"를 포함하지 않는 것이 중요합니다.

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:>