Sur cette page

Client CoAP simple

Créer une application qui communique avec un serveur CoAP.

Fenêtre du client CoAP avec la boîte de dialogue Add Options et les ressources découvertes

Simple CoAP Client montre comment créer une application client CoAP minimaliste pour envoyer et recevoir des messages CoAP.

Exécution de l'exemple

Pour exécuter l'exemple à partir de Qt CreatorOuvrez le mode Welcome et sélectionnez l'exemple à partir de Examples. Pour plus d'informations, voir Qt Creator: Tutorial : Construire et exécuter.

Configuration d'un serveur CoAP

Pour utiliser l'application, vous devez spécifier un serveur CoAP. Vous avez les options suivantes :

  • Utiliser le serveur de test CoAP situé à l'adresse coap://coap.me.
  • Créer un serveur CoAP en utilisant libcoap, FreeCoAP ou toute autre implémentation de serveur CoAP.
  • Utiliser le serveur plugtest de Californium, qui prend en charge la plupart des fonctionnalités CoAP. Vous pouvez le construire manuellement ou utiliser une image Docker prête à l'emploi, qui construit et démarre le serveur plugtest. Les étapes pour utiliser le serveur basé sur Docker sont décrites ci-dessous.
Utilisation du serveur de test basé sur Docker

La commande suivante extrait le conteneur Docker pour le serveur CoAP du Docker Hub et le démarre :

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

Pour connaître l'adresse IP du conteneur Docker, récupérez d'abord l'ID du conteneur en exécutant docker ps, ce qui donnera quelque chose comme :

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

Vous pouvez ensuite obtenir l'adresse IP à l'aide de la commande suivante :

docker inspect <container_id> | grep IPAddress

Par exemple :

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

Le serveur de test CoAP sera accessible par l'adresse IP récupérée sur les ports 5683 (non sécurisé) et 5684 (sécurisé).

Pour terminer le conteneur docker après utilisation, utilisez la commande suivante :

docker stop <container_id>

L'adresse <container_id> est la même que celle récupérée par la commande docker ps.

Création d'un client

La première étape consiste à créer un client CoAP en utilisant la classe QCoapClient. Ensuite, nous devons connecter ses signaux, afin d'être notifiés lorsqu'une réponse CoAP est reçue ou qu'une requête a échoué :

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);
    ...

Envoi de requêtes

Nous utilisons la classe QCoapRequest pour créer des requêtes CoAP. Cette classe fournit des méthodes pour construire des trames CoAP.

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);
    ...

Dans cet exemple, nous définissons l'URL, ainsi que le type de message et nous ajoutons des options à la demande. Il est également possible de définir la charge utile, l'ID du message, le jeton, etc., mais nous utilisons ici les valeurs par défaut. Notez que par défaut, l'ID du message et le jeton sont générés de manière aléatoire.

En fonction de la méthode de requête sélectionnée, nous envoyons une requête GET, PUT, POST ou DELETE au serveur :

    ...
    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;
    }
    ...

Pour les requêtes PUT et POST, nous ajoutons également m_currentData en tant que charge utile de la requête.

Pour parcourir le contenu du serveur et découvrir les ressources qui y sont disponibles, on utilise une requête de découverte:

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

Remarque : au lieu de la classe QCoapReply, nous utilisons la classe QCoapResourceDiscoveryReply pour conserver la réponse à une demande de découverte. Elle possède le signal QCoapResourceDiscoveryReply::discovered, qui renvoie la liste des QCoapResources qui ont été découvertes.

S'il existe des ressources observables sur le serveur (ce qui signifie qu'elles ont le type de ressource obs), nous pouvons nous abonner aux mises à jour de cette ressource en lançant une demande d'observation:

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

Le client peut se désabonner de l'observation de la ressource en traitant le signal clicked() de la requête cancelObserveButton:

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

Les réponses provenant du serveur sont affichées dans l'interface utilisateur :

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;
}

Files :

© 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.