이 페이지에서

간단한 CoAP 클라이언트

CoAP 서버와 통신하는 애플리케이션 만들기.

‘옵션 추가’ 대화 상자와 검색된 리소스가 표시된 CoAP 클라이언트 창

'간단한 CoAP 클라이언트'는 CoAP 메시지를 송수신하는 최소한의 CoAP 클라이언트 애플리케이션을 만드는 방법을 보여줍니다.

예제 실행

다음 위치에서 예제를 실행할 수 있습니다:

CoAP 서버 설정

애플리케이션을 사용하려면 CoAP 서버를 지정해야 합니다. 다음 옵션을 사용할 수 있습니다.

  • coap://coap.me 에 위치한 CoAP 테스트 서버를 사용합니다.
  • libcoap, FreeCoAP 또는 기타 CoAP 서버 구현체를 사용하여 CoAP 서버를 생성합니다.
  • 대부분의 CoAP 기능을 지원하는 Californium plugtest 서버를 사용합니다. 수동으로 빌드하거나, 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 테스트 서버는 검색한 IP 주소의 5683번 포트(비보안) 및 5684번 포트(보안)를 통해 접속할 수 있습니다.

사용 후 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와 토큰은 무작위로 생성된다는 점에 유의하십시오.

선택한 요청 메서드에 따라 서버로 GET, PUT, POST 또는 DELETE 요청을 전송합니다.

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

PUT 및 POST 요청의 경우, 요청의 페이로드로 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 신호가 있으며, 이 신호는 발견된 QCoapResource 목록을 반환합니다.

서버에 관찰 가능한 리소스(즉, 리소스 유형이 obs 인 리소스)가 있는 경우, observe 요청을 실행하여 해당 리소스의 업데이트를 구독할 수 있습니다:

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

클라이언트는 cancelObserveButton 의 clicked() 신호를 처리하여 리소스 관찰을 해제할 수 있습니다:

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

파일:

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