Einfacher CoAP-Client
Erstellen einer Anwendung, die mit einem CoAP-Server kommuniziert.
Simple CoAP Client zeigt, wie man eine minimalistische CoAP-Client-Anwendung zum Senden und Empfangen von CoAP-Nachrichten erstellt.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel unter Examples aus. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.
Einrichten eines CoAP-Servers
Um die Anwendung zu verwenden, müssen Sie einen CoAP-Server angeben. Sie haben die folgenden 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.
Verwenden des Docker-basierten Test-Servers
Der folgende Befehl zieht den Docker-Container für den CoAP-Server aus dem Docker Hub 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 herauszufinden, rufen Sie zunächst die Container-ID durch Ausführen von docker ps
ab, was eine Ausgabe wie diese ergibt:
$ 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
Zum Beispiel:
$ docker inspect 5e46502df88f | grep IPAddress ... "IPAddress": "172.17.0.2", ...
Der CoAP-Testserver ist über die ermittelte IP-Adresse auf den Ports 5683 (nicht sicher) und 5684 (sicher) erreichbar.
Um den Docker-Container nach der Verwendung zu beenden, verwenden Sie den folgenden Befehl:
docker stop <container_id>
Die <container_id>
ist hier die gleiche wie die, die mit dem Befehl docker ps
abgerufen wird.
Erstellen eines Clients
Der erste Schritt besteht darin, einen CoAP-Client mit der Klasse QCoapClient zu erstellen. Dann müssen wir seine 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); ...
Senden von Anfragen
Wir verwenden die Klasse QCoapRequest, um CoAP-Anfragen zu erstellen. Diese Klasse bietet Methoden zur Erstellung von CoAP-Frames.
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 Nutzlast, die Nachrichten-ID, das Token usw. festzulegen, aber wir verwenden hier die Standardwerte. Beachten Sie, dass die Nachrichten-ID und das Token standardmäßig nach dem Zufallsprinzip generiert werden.
Je nach gewählter Anfragemethode senden wir eine GET
, PUT
, POST
oder 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 den Anfragen PUT
und POST
fügen wir auch m_currentData
als Nutzdaten für die Anfrage hinzu.
Um den Inhalt des Servers zu durchsuchen und die auf ihm verfügbaren Ressourcen zu ermitteln, wird eine Discovery-Anfrage 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 speichern. Sie hat das Signal QCoapResourceDiscoveryReply::discovered, das die Liste der entdeckten QCoapResources zurückgibt.
Wenn es auf dem Server beobachtbare Ressourcen gibt (d. h. sie haben den Ressourcentyp obs
), können wir Aktualisierungen dieser Ressource abonnieren, indem wir eine Beobachtungsanforderung ausführen:
void MainWindow::on_observeButton_clicked() { ... QCoapReply *observeReply = m_client->observe(url); ... connect(observeReply, &QCoapReply::notified, this, &MainWindow::onNotified); ...
Der Client kann sich von der Ressourcenbeobachtung abmelden, indem er das Signal clicked()
der 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:
© 2025 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.