Schneller, sicherer CoAP-Client
Sichern des CoAP-Clients und dessen Verwendung mit einer Benutzeroberfläche von „ Qt Quick “.

„Quick Secure CoAP Client“ zeigt, wie man einen sicheren CoAP-Client erstellt und ihn in einer „ Qt Quick “-Anwendung einsetzt.
Hinweis: „ Qt CoAP “ bietet in der aktuellen Version keine QML-API. Sie können jedoch die C++-Klassen des Moduls für QML verfügbar machen, wie im Beispiel gezeigt.
Ausführen des Beispiels
Sie können das Beispiel wie folgt ausführen:
- Qt Creator
Öffnen Sie den Welcome -Modus und wählen Sie das Beispiel unter „ Examples “ aus. Weitere Informationen finden Sie unter Qt Creator: Tutorial: Erstellen und Ausführen.
- Qt Extension for Visual Studio Code
Führen Sie den Befehl „ Qt: Open Qt examples “ aus dem Ordner „ Command Palette “ aus und wählen Sie das Beispiel aus der Liste aus. Weitere Informationen finden Sie unter Qt Extension for Visual Studio Code: Tutorial: Erstellen und Ausführen.
Um die Beispielanwendung auszuführen, müssen Sie zunächst einen sicheren CoAP-Server einrichten. Sie können das Beispiel mit jedem sicheren CoAP-Server ausführen, der einen der Authentifizierungsmodi „Pre-Shared Key“ (PSK) oder „Zertifikat“ unterstützt. Weitere Informationen zum Einrichten eines sicheren CoAP-Servers finden Sie unter „Einrichten eines sicheren CoAP-Servers“.
C++-Klassen für QML verfügbar machen
In diesem Beispiel müssen Sie die Klasse ` QCoapClient ` und den Namespace ` QtCoap ` für QML verfügbar machen. Erstellen Sie dazu eine benutzerdefinierte Wrapper-Klasse und verwenden Sie die speziellen Registrierungsmakros.
Erstellen Sie die Klasse „ QmlCoapSecureClient “ als Wrapper für „ QCoapClient “. Diese Klasse enthält außerdem den ausgewählten Sicherheitsmodus und die Sicherheitskonfigurationsparameter. Verwenden Sie das Makro „ Q_INVOKABLE “, um mehrere Methoden für QML verfügbar zu machen. Verwenden Sie außerdem das Makro „ QML_NAMED_ELEMENT “, um die Klasse in QML als „ CoapSecureClient “ zu registrieren.
class QmlCoapSecureClient : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(CoapSecureClient)
public:
QmlCoapSecureClient(QObject *parent = nullptr);
~QmlCoapSecureClient() override;
Q_INVOKABLE void setSecurityMode(QtCoap::SecurityMode mode);
Q_INVOKABLE void sendGetRequest(const QString &host, const QString &path, int port);
Q_INVOKABLE void setSecurityConfiguration(const QString &preSharedKey, const QString &identity);
Q_INVOKABLE void setSecurityConfiguration(const QString &localCertificatePath,
const QString &caCertificatePath,
const QString &privateKeyPath);
Q_INVOKABLE void disconnect();
Q_SIGNALS:
void finished(const QString &result);
private:
QCoapClient *m_coapClient;
QCoapSecurityConfiguration m_configuration;
QtCoap::SecurityMode m_securityMode;
};Registrieren Sie anschließend den Namespace „ QtCoap “, damit Sie die dort bereitgestellten Enums verwenden können:
namespace QCoapForeignNamespace
{
Q_NAMESPACE
QML_FOREIGN_NAMESPACE(QtCoap)
QML_NAMED_ELEMENT(QtCoap)
}Anpassung der Build-Dateien
Um die benutzerdefinierten Typen in QML verfügbar zu machen, aktualisieren Sie die Build-System-Dateien entsprechend.
CMake
Fügen Sie bei einem CMake-basierten Build Folgendes zur Datei „ CMakeLists.txt “ hinzu:
qt_add_qml_module(quicksecureclient
URI CoapSecureClientModule
SOURCES
qmlcoapsecureclient.cpp qmlcoapsecureclient.h
QML_FILES
FilePicker.qml
Main.qml
)qmake
Für einen qmake-Build ändern Sie die Datei „ quicksecureclient.pro “ wie folgt:
CONFIG += qmltypes
QML_IMPORT_NAME = CoapSecureClientModule
QML_IMPORT_MAJOR_VERSION = 1
...
qml_resources.files = \
qmldir \
FilePicker.qml \
Main.qml
qml_resources.prefix = /qt/qml/CoapSecureClientModule
RESOURCES += qml_resourcesVerwendung der neuen QML-Typen
Sobald die C++-Klassen ordnungsgemäß für QML verfügbar sind, können Sie die neuen Typen verwenden.
Erstellen des Clients
CoapSecureClient wird aus der Datei „ Main.qml “ instanziiert. Er verarbeitet das Signal „ QmlCoapSecureClient::finished() “ und aktualisiert die Benutzeroberfläche entsprechend:
CoapSecureClient {
id: client
onFinished: (result) => {
outputView.text = result;
statusLabel.text = "";
disconnectButton.enabled = true;
}
}Die Instanz von ` QCoapClient ` wird erstellt, wenn der Benutzer den Sicherheitsmodus in der Benutzeroberfläche auswählt oder ändert. Die Methode ` QmlCoapSecureClient::setSecurityMode() ` wird aus dem QML-Code aufgerufen, sobald einer der Sicherheitsmodi ausgewählt wird:
ButtonGroup {
id: securityModeGroup
onClicked: {
if ((securityModeGroup.checkedButton as RadioButton) === preSharedMode)
client.setSecurityMode(QtCoap.SecurityMode.PreSharedKey);
else
client.setSecurityMode(QtCoap.SecurityMode.Certificate);
}
}Auf der C++-Seite erstellt diese Methode ein ` QCoapClient `-Objekt und verbindet sich mit dessen Signalen ` finished()` und ` error()`. Die Klasse verarbeitet beide Signale intern und leitet sie an das neue Signal ` finished() ` weiter.
void QmlCoapSecureClient::setSecurityMode(QtCoap::SecurityMode mode)
{
// Create a new client, if the security mode has changed
if (m_coapClient && mode != m_securityMode) {
delete m_coapClient;
m_coapClient = nullptr;
}
if (!m_coapClient) {
m_coapClient = new QCoapClient(mode);
m_securityMode = mode;
connect(m_coapClient, &QCoapClient::finished, this,
[this](QCoapReply *reply) {
if (!reply)
emit finished(tr("Something went wrong, received a null reply"));
else if (reply->errorReceived() != QtCoap::Error::Ok)
emit finished(errorMessage(reply->errorReceived()));
else
emit finished(reply->message().payload());
});
connect(m_coapClient, &QCoapClient::error, this,
[this](QCoapReply *, QtCoap::Error errorCode) {
emit finished(errorMessage(errorCode));
});
}
}Senden einer Anforderung
Klicken Sie auf die Schaltfläche „ Send Request “, um die Sicherheitskonfiguration basierend auf dem ausgewählten Sicherheitsmodus festzulegen und eine „ GET “-Anfrage zu senden:
Button {
id: requestButton
text: qsTr("Send Request")
enabled: securityModeGroup.checkState !== Qt.Unchecked
onClicked: {
outputView.text = "";
if ((securityModeGroup.checkedButton as RadioButton) === preSharedMode)
client.setSecurityConfiguration(pskField.text, identityField.text);
else
client.setSecurityConfiguration(localCertificatePicker.selectedFile,
caCertificatePicker.selectedFile,
privateKeyPicker.selectedFile);
client.sendGetRequest(hostComboBox.editText, resourceField.text,
parseInt(portField.text));
statusLabel.text = qsTr("Sending request to %1%2...").arg(hostComboBox.editText)
.arg(resourceField.text);
}
}Es gibt zwei Überladungen für die Methode „ setSecurityConfiguration “.
Die Überladung für den PSK-Modus legt lediglich die Client-Identität und den vorab geteilten Schlüssel fest:
void
QmlCoapSecureClient::setSecurityConfiguration(const QString &preSharedKey, const QString &identity)
{
QCoapSecurityConfiguration configuration;
configuration.setPreSharedKey(preSharedKey.toUtf8());
configuration.setPreSharedKeyIdentity(identity.toUtf8());
m_configuration = configuration;
}Die Überladung für X.509-Zertifikate liest die Zertifikatsdateien und den privaten Schlüssel ein und legt die Sicherheitskonfiguration fest:
void QmlCoapSecureClient::setSecurityConfiguration(const QString &localCertificatePath,
const QString &caCertificatePath,
const QString &privateKeyPath)
{
QCoapSecurityConfiguration configuration;
const auto localCerts =
QSslCertificate::fromPath(QUrl(localCertificatePath).toLocalFile(), QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString);
if (localCerts.isEmpty())
qCWarning(lcCoapClient, "The specified local certificate file is not valid.");
else
configuration.setLocalCertificateChain(localCerts.toVector());
const auto caCerts = QSslCertificate::fromPath(QUrl(caCertificatePath).toLocalFile(), QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString);
if (caCerts.isEmpty())
qCWarning(lcCoapClient, "The specified CA certificate file is not valid.");
else
configuration.setCaCertificates(caCerts.toVector());
QFile privateKey(QUrl(privateKeyPath).toLocalFile());
if (privateKey.open(QIODevice::ReadOnly)) {
QCoapPrivateKey key(privateKey.readAll(), QSsl::Ec);
configuration.setPrivateKey(key);
} else {
qCWarning(lcCoapClient) << "Unable to read the specified private key file"
<< privateKeyPath;
}
m_configuration = configuration;
}Nach dem Festlegen der Sicherheitskonfiguration legt die Methode „ sendGetRequest “ die Anfrage-URL fest und sendet eine „ GET “-Anfrage:
void QmlCoapSecureClient::sendGetRequest(const QString &host, const QString &path, int port)
{
if (!m_coapClient)
return;
m_coapClient->setSecurityConfiguration(m_configuration);
QUrl url;
url.setHost(host);
url.setPath(path);
url.setPort(port);
m_coapClient->get(url);
}Beim Senden der ersten Anfrage wird ein Handshake mit dem CoAP-Server durchgeführt. Nach erfolgreichem Abschluss des Handshakes werden alle nachfolgenden Nachrichten verschlüsselt, und eine Änderung der Sicherheitskonfiguration nach einem erfolgreichen Handshake hat keine Auswirkungen. Wenn Sie diese ändern oder den Host wechseln möchten, müssen Sie zunächst die Verbindung trennen.
void QmlCoapSecureClient::disconnect()
{
if (m_coapClient)
m_coapClient->disconnect();
}Dadurch wird der Handshake abgebrochen und die offenen Sockets geschlossen.
Für die Authentifizierung mit X.509-Zertifikaten müssen die Zertifikatsdateien angegeben werden. Zu diesem Zweck wird die Komponente „ FilePicker “ verwendet. Sie besteht aus einem Textfeld und einer Schaltfläche, die beim Klicken einen Dateidialog öffnet:
Item {
id: filePicker
property string dialogText
property alias selectedFile: filePathField.text
height: addFileButton.height
FileDialog {
id: fileDialog
title: qsTr("Please Choose %1").arg(filePicker.dialogText)
currentFolder: StandardPaths.writableLocation(StandardPaths.HomeLocation)
fileMode: FileDialog.OpenFile
onAccepted: filePathField.text = fileDialog.selectedFile
}
RowLayout {
anchors.fill: parent
TextField {
id: filePathField
placeholderText: qsTr("<%1>").arg(filePicker.dialogText)
inputMethodHints: Qt.ImhUrlCharactersOnly
selectByMouse: true
Layout.fillWidth: true
}
Button {
id: addFileButton
text: qsTr("Add %1").arg(filePicker.dialogText)
onClicked: fileDialog.open()
}
}
}FilePicker wird in der Datei „ Main.qml “ mehrfach instanziiert, um Eingabefelder für Zertifikate und den privaten Schlüssel zu erstellen:
FilePicker {
id: localCertificatePicker
dialogText: qsTr("Local Certificate")
enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode
Layout.columnSpan: 2
Layout.fillWidth: true
}
FilePicker {
id: caCertificatePicker
dialogText: qsTr("CA Certificate")
enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode
Layout.columnSpan: 2
Layout.fillWidth: true
}
FilePicker {
id: privateKeyPicker
dialogText: qsTr("Private Key")
enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode
Layout.columnSpan: 2
Layout.fillWidth: true
}Einrichten eines sicheren CoAP-Servers
Um dieses Beispiel auszuführen, benötigen Sie einen sicheren CoAP-Server, der entweder den PSK- oder den Zertifikatsmodus (oder beide) unterstützt. Sie haben folgende Möglichkeiten:
- Erstellen und betreiben Sie manuell einen sicheren CoAP-Server, beispielsweise mit libcoap, Californium, FreeCoAP oder einer anderen CoAP-Bibliothek, die DTLS unterstützt.
- Verwenden Sie die auf Docker Hub verfügbaren vorgefertigten Docker-Images, mit denen sich für unser Beispiel geeignete sichere CoAP-Server erstellen und ausführen lassen. Die erforderlichen Schritte zur Verwendung der Docker-basierten CoAP-Server werden im Folgenden beschrieben.
Einrichten eines Servers für den PSK-Modus
Der folgende Befehl ruft den Docker-Container für einen sicheren CoAP-Server auf Basis von Californium plugtest (der standardmäßig nicht sicher ist) von 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.0Der CoAP-Testserver ist über die Ports 5683 (unsicher) und 5684 (sicher) erreichbar. Anweisungen zum Abrufen der IP-Adresse finden Sie unter „IP-Adresse abrufen“.
Um das Beispiel mit diesem Server auszuführen, müssen Sie den vorab geteilten Schlüssel auf „ secretPSK “ und die Identität auf „ Client_identity “ setzen.
Einrichten eines Servers für den Zertifikatsmodus
Das Docker-Image des sicheren Servers, der die Authentifizierung mit X.509-Zertifikaten nutzt, basiert auf dem Zeit-Server -Beispiel aus der FreeCoAP-Bibliothek. Der folgende Befehl ruft den Container von Docker Hub ab und startet ihn:
docker run --name coap-time-server -d --rm -p 5684:5684/udp tqtc/coap-secure-time-server:freecoapAnweisungen zum Abrufen der IP-Adresse finden Sie unter „IP-Adresse abrufen“. Der CoAP-Testserver ist über die abgerufene IP-Adresse am Port 5684 und unter dem Ressourcenpfad /time erreichbar.
Um das Beispiel mit diesem Server auszuführen, müssen Sie die vom Server benötigten Zertifikatsdateien angeben. Diese befinden sich im Docker-Container im Verzeichnis „ /root/certs “. Um sie in ein lokales Verzeichnis zu kopieren, verwenden Sie den folgenden Befehl:
docker cp <container_id>:/root/certs <local_directory_path>Beispiel:
$ docker cp 5e46502df88f:/root/certs ~/Die Anleitung zum Abrufen der Container-ID wird im Folgenden beschrieben.
Ermitteln der IP-Adresse
Um die IP-Adresse eines Docker-Containers zu ermitteln, rufen Sie zunächst die Container-ID ab, indem Sie den Befehl ` docker ps ` ausführen, der etwa folgende Ausgabe liefert:
$ docker ps
CONTAINER ID IMAGE
5e46502df88f tqtc/coap-californium-test-server:3.8.0Anschließend können Sie die IP-Adresse mit dem folgenden Befehl abrufen:
docker inspect <container_id> | grep IPAddressBeispiel:
$ docker inspect 5e46502df88f | grep IPAddress
...
"IPAddress": "172.17.0.2",
...Beenden eines Docker-Containers
Um einen Docker-Container nach der Nutzung zu beenden, verwenden Sie den folgenden Befehl:
docker stop <container_id>Die hier verwendete ` <container_id> ` entspricht der durch den Befehl ` docker ps ` ermittelten ID.
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.