Auf dieser Seite

Einfacher CoAP-Client

Erstellen einer Anwendung, die mit einem CoAP-Server kommuniziert.

CoAP-Client-Fenster mit dem Dialogfeld „Optionen hinzufügen“ und den erkannten Ressourcen

„Einfacher CoAP-Client“ zeigt, wie man eine minimalistische CoAP-Client-Anwendung erstellt, um CoAP-Nachrichten zu senden und zu empfangen.

Ausführen des Beispiels

Sie können das Beispiel wie folgt ausführen:

Einrichten eines CoAP-Servers

Um die Anwendung nutzen zu können, müssen Sie einen CoAP-Server angeben. Sie haben folgende Möglichkeiten:

  • Verwenden Sie den CoAP-Testserver unter coap://coap.me.
  • Erstellen Sie einen CoAP-Server mit libcoap, FreeCoAP oder einer anderen CoAP-Server-Implementierung.
  • Verwenden Sie den Californium-Plugtest-Server, der die meisten CoAP-Funktionen unterstützt. Sie können ihn manuell erstellen oder ein fertiges Docker-Image verwenden, das den Plugtest-Server erstellt und startet. Die Schritte zur Verwendung des Docker-basierten Servers werden im Folgenden beschrieben.
Verwendung des Docker-basierten Test-Servers

Der folgende Befehl ruft den Docker-Container für den CoAP-Server vom Docker Hub ab und startet ihn:

docker run --name coap-test-server -d --rm -p 5683:5683/udp -p 5684:5684/udp tqtc/coap-californium-test-server:3.8.0

Um die IP-Adresse des Docker-Containers zu ermitteln, rufen Sie zunächst die Container-ID ab, indem Sie den Befehl „ docker ps “ ausführen. Die Ausgabe sieht in etwa so aus:

$ docker ps
CONTAINER ID        IMAGE
5e46502df88f        tqtc/coap-californium-test-server:3.8.0

Anschließend können Sie die IP-Adresse mit dem folgenden Befehl abrufen:

docker inspect <container_id> | grep IPAddress

Beispiel:

$ docker inspect 5e46502df88f | grep IPAddress
...
"IPAddress": "172.17.0.2",
...

Der CoAP-Testserver ist über die abgerufene IP-Adresse auf den Ports 5683 (ungesichert) und 5684 (gesichert) erreichbar.

Um den Docker-Container nach der Nutzung zu beenden, verwenden Sie den folgenden Befehl:

docker stop <container_id>

Die hier angegebene „ <container_id> “ entspricht der durch den Befehl „ docker ps “ ermittelten ID.

Erstellen eines Clients

Der erste Schritt besteht darin, mithilfe der Klasse „ QCoapClient “ einen CoAP-Client zu erstellen. Anschließend müssen wir dessen Signale verbinden, um benachrichtigt zu werden, wenn eine CoAP-Antwort empfangen wird oder eine Anfrage fehlgeschlagen ist:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    m_client = new QCoapClient(QtCoap::SecurityMode::NoSecurity, this);
    connect(m_client, &QCoapClient::finished, this, &MainWindow::onFinished);
    connect(m_client, &QCoapClient::error, this, &MainWindow::onError);
    ...

Anfragen senden

Wir verwenden die Klasse ` QCoapRequest `, um CoAP-Anfragen zu erstellen. Diese Klasse stellt Methoden zum Erstellen von CoAP-Frames bereit.

void MainWindow::on_runButton_clicked()
{
    const auto msgType = ui->msgTypeCheckBox->isChecked() ? QCoapMessage::Type::Confirmable
                                                          : QCoapMessage::Type::NonConfirmable;
    QUrl url;
    url.setHost(tryToResolveHostName(ui->hostComboBox->currentText()));
    url.setPort(ui->portSpinBox->value());
    url.setPath(ui->resourceComboBox->currentText());

    QCoapRequest request(url, msgType);
    for (const auto &option : std::as_const(m_options))
        request.addOption(option);
    ...

In diesem Beispiel legen wir die URL sowie den Nachrichtentyp fest und fügen der Anfrage Optionen hinzu. Es ist auch möglich, die Nutzdaten, die Nachrichten-ID, das Token usw. festzulegen, aber wir verwenden hier die Standardwerte. Beachten Sie, dass die Nachrichten-ID und das Token standardmäßig zufällig generiert werden.

Je nach gewählter Anfragemethode senden wir eine „ GET “-Anfrage, eine „ PUT “-Anfrage, eine „ POST “-Anfrage oder eine „ DELETE “-Anfrage an den Server:

    ...
    switch (method) {
    case QtCoap::Method::Get:
        m_client->get(request);
        break;
    case QtCoap::Method::Put:
        m_client->put(request, m_currentData);
        break;
    case QtCoap::Method::Post:
        m_client->post(request, m_currentData);
        break;
    case QtCoap::Method::Delete:
        m_client->deleteResource(request);
        break;
    default:
        break;
    }
    ...

Bei PUT - und POST -Anfragen fügen wir außerdem m_currentData als Nutzdaten für die Anfrage hinzu.

Um den Inhalt des Servers zu durchsuchen und die darauf verfügbaren Ressourcen zu ermitteln, wird eine Erkundungsanfrage verwendet:

void MainWindow::on_discoverButton_clicked()
{
    ...
    QCoapResourceDiscoveryReply *discoverReply =
            m_client->discover(url, ui->discoveryPathEdit->text());
    if (discoverReply) {
        connect(discoverReply, &QCoapResourceDiscoveryReply::discovered,
                this, &MainWindow::onDiscovered);
    ...

Hinweis: Anstelle der Klasse „ QCoapReply “ verwenden wir die Klasse „ QCoapResourceDiscoveryReply “, um die Antwort auf eine Discovery-Anfrage zu erhalten. Diese verfügt über das Signal „ QCoapResourceDiscoveryReply::discovered “, das die Liste der entdeckten QCoapResources zurückgibt.

Wenn auf dem Server beobachtbare Ressourcen vorhanden sind (d. h., sie haben den Ressourcentyp „ obs “), können wir Updates zu dieser Ressource abonnieren, indem wir eine Beobachtungsanfrage ausführen:

void MainWindow::on_observeButton_clicked()
{
    ...
    QCoapReply *observeReply = m_client->observe(url);
    ...
    connect(observeReply, &QCoapReply::notified, this, &MainWindow::onNotified);
    ...

Der Client kann die Beobachtung der Ressource beenden, indem er das Signal „ clicked() “ des „ cancelObserveButton “ verarbeitet:

    ...
    connect(ui->cancelObserveButton, &QPushButton::clicked, this, [this, url]() {
        m_client->cancelObserve(url);
        ui->cancelObserveButton->setEnabled(false);
    });

Die vom Server kommenden Antworten werden in der Benutzeroberfläche angezeigt:

void MainWindow::addMessage(const QString &message, bool isError)
{
    const QString content = "--------------- %1 ---------------\n%2\n\n"_L1
                                .arg(QDateTime::currentDateTime().toString(), message);
    ui->textEdit->setTextColor(isError ? Qt::red : Qt::black);
    ui->textEdit->insertPlainText(content);
    ui->textEdit->ensureCursorVisible();
}

void MainWindow::onFinished(QCoapReply *reply)
{
    if (reply->errorReceived() == QtCoap::Error::Ok)
        addMessage(reply->message().payload());
}

static QString errorMessage(QtCoap::Error errorCode)
{
    const auto error = QMetaEnum::fromType<QtCoap::Error>().valueToKey(static_cast<int>(errorCode));
    return MainWindow::tr("Request failed with error: %1\n").arg(error);
}

void MainWindow::onError(QCoapReply *reply, QtCoap::Error error)
{
    const auto errorCode = reply ? reply->errorReceived() : error;
    addMessage(errorMessage(errorCode), true);
}

void MainWindow::onDiscovered(QCoapResourceDiscoveryReply *reply, QList<QCoapResource> resources)
{
    if (reply->errorReceived() != QtCoap::Error::Ok)
        return;

    QString message;
    for (const auto &resource : std::as_const(resources)) {
        ui->resourceComboBox->addItem(resource.path());
        message += tr("Discovered resource: \"%1\" on path %2\n")
                        .arg(resource.title(), resource.path());
    }
    addMessage(message);
}

void MainWindow::onNotified(QCoapReply *reply, const QCoapMessage &message)
{
    if (reply->errorReceived() == QtCoap::Error::Ok) {
        addMessage(tr("Received observe notification with payload: %1")
                        .arg(QString::fromUtf8(message.payload())));
    }
}

static QString tryToResolveHostName(const QString hostName)
{
    const auto hostInfo = QHostInfo::fromName(hostName);
    if (!hostInfo.addresses().empty())
        return hostInfo.addresses().first().toString();

    return hostName;
}

Dateien:

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.