シンプルなCoAPクライアント

CoAPサーバーと通信するアプリケーションの作成。

Simple CoAP Clientは、CoAPメッセージを送受信するための最小限のCoAPクライアント・アプリケーションを作成する方法を示します。

サンプルを実行する

Qt Creator からサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳しくは、Building and Running an Example を参照してください。

CoAP サーバーのセットアップ

アプリケーションを使用するには、CoAP サーバーを指定する必要があります。以下のオプションがあります:

  • coap://coap.me にある CoAP テスト・サーバーを使用する。
  • libcoapFreeCoAP、またはその他のCoAPサーバー実装を使用してCoAPサーバーを作成する。
  • CoAP機能のほとんどをサポートするCaliforniumplugtestサーバーを使用する。手動で構築することも、plugtestサーバーを構築して起動する準備のできたDockerイメージを使用することもできる。Dockerベースのサーバーを使用する手順を以下に説明する。
Docker ベースのテスト・サーバーの使用

以下のコマンドで、Docker Hub から CoAP サーバー用の docker コンテナを取り出し、起動します:

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

docker コンテナの IP アドレスを調べるには、まずdocker ps を実行してコンテナ ID を取得する:

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

次に、以下のコマンドで IP アドレスを取得できる:

docker inspect <container_id> | grep IPAddress

例えば

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

CoAP テスト・サーバーは、ポート5683(非セキュア)とポート5684(セキュア)で、取得した IP アドレスで到達可能である。

使用後に docker コンテナを終了するには、以下のコマンドを使用する:

docker stop <container_id>

ここでの<container_id>docker ps コマンドで取得したものと同じである。

クライアントの作成

最初のステップは、QCoapClient クラスを使って CoAP クライアントを作成することである。そして、CoAPリプライを受信した時やリクエストが失敗した時に通知を受け取るために、シグナルを接続する必要がある:

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

リクエストの送信

QCoapRequest クラスを使って CoAP リクエストを作成する。このクラスは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);
    ...

この例では、URL とメッセージタイプを設定し、リクエストにオプションを追加します。ペイロード、メッセージ ID、トークンなどを設定することも可能ですが、ここではデフォルト値を使用しています。デフォルトでは、メッセージIDとトークンはランダムに生成されます。

選択したリクエストメソッドに基づいて、GETPUTPOSTDELETE のリクエストをサーバーに送る:

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

PUTPOST のリクエストには、m_currentData をリクエストのペイロードとして追加します。

サーバーのコンテンツをブラウズし、サーバー上で利用可能なリソースを発見するために、発見リクエストが使われる:

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

注: QCoapReply クラスの代わりに、QCoapResourceDiscoveryReply を使用して、発見リクエストに対する応答を保持します。これはQCoapResourceDiscoveryReply::discovered シグナルを持ち、発見されたQCoapResourcesのリストを返します。

サーバー上にobserve可能なリソースがある場合(リソースタイプがobs)、observeリクエストを実行することで、そのリソースの更新を購読することができる:

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

クライアントはcancelObserveButtonclicked() シグナルを処理することで、リソースのオブザベーションの購読を解除することができる:

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

サーバーからのレスポンスはUIに表示されます:

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

ファイル

本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。