センサー

Sensorsの例では、UDPソケットを使用してprotobufメッセージを送信することで、2つのアプリケーションがどのように通信できるかを示しています。

Sensors のサンプルは以下のコンポーネントで構成されています:

  • protobuf_sensors qt_add_protobuf呼び出しを使用して protobuf スキーマから生成するライブラリ。
  • protobuf_sensor_emulator 単純なセンサーの動作をエミュレートするアプリケーション
  • protobuf_sensors_client UDP ソケットからのセンサーデータを表示するアプリケーション。

クライアントアプリケーションはlocalhost UDP ポート65500 にバインドし、エミュレータアプリケーションからのデータを待ちます。

エミュレータアプリケーションを使用してセンサーデータの値を変更し、クライアントの UDP ポートにデータを送信します。

アプリケーションはprotobuf_sensors ライブラリから生成されたメッセージを使用して通信します。ライブラリは .proto ファイルに記述された protobuf スキーマから生成されます。

qt_add_protobuf(protobuf_sensors
    PROTO_FILES
        sensors.proto
        tlv.proto
)

最初のファイルには Type-Length-Value メッセージが記述されており、センサーデータをラップしている:

package qt.examples.sensors.tlv;

enum MessageType {
    Coordinates = 0;
    Temperature = 1;
    WarningNotification = 2;
}

// Protobuf messages imply inline data size.
message TlvMessage {
    MessageType type = 1;
    bytes value = 2;
}

2 番目の .proto ファイルにはセンサーメッセージの記述がある:

package qt.examples.sensors;

message Coordinates {
    double longitude = 1;
    double latitude = 2;
    double altitude = 3;
}

message Temperature {
    enum Unit {
        Farenheit = 0;
        Celsius = 1;
    }
    sint32 value = 1;
    Unit units = 2;
}

message WarningNotification {
    string text = 1;
}

メッセージはQProtobufSerializer を使ってシリアライズされる:

class SensorClient : public QObject
{
    Q_OBJECT
...
private:
    QUdpSocket m_client;
    QProtobufSerializer m_serializer;
};

そしてエミュレータ:

class SensorEmulator : public QObject
{
    Q_OBJECT
...
    QUdpSocket m_socket;
    QProtobufSerializer m_serializer;
};

エミュレータ:エミュレータアプリケーションでSend ボタンをクリックすると、QLineEdit フィールドのデータが文字列フォーマットからメッセージフィールド固有のフォーマットに変換されます:

    QObject::connect(ui->sendCoordinates, &QPushButton::clicked, this, [this]() {
        qt::examples::sensors::Coordinates coord;
        coord.setLatitude(ui->latitudeValue->text().toDouble());
        coord.setLongitude(ui->longitudeValue->text().toDouble());
        coord.setAltitude(ui->altitudeValue->text().toDouble());
        emit coordinatesUpdated(coord);
    });

次に、すべてのフィールドを含むメッセージがシリアライズされ、Type-Length-Value メッセージでラップされる:

    Q_ASSERT(serializer != nullptr);
    tlv::TlvMessage msg;
    msg.setType(type);
    msg.setValue(data);
    return msg.serialize(serializer);

クライアントは受信したデータグラムに対して逆の処理を行う。まず Type-Length-Value メッセージがデータグラムデータからデシリアライズされる:

        const auto datagram = m_client.receiveDatagram();
        qt::examples::sensors::tlv::TlvMessage msg;
        msg.deserialize(&m_serializer, datagram.data());
        if (m_serializer.lastError()
                != QAbstractProtobufSerializer::Error::None) {
            qWarning().nospace() << "Unable to deserialize datagram ("
                       << qToUnderlying(m_serializer.lastError()) << ")"
                       << m_serializer.lastErrorString();
            continue;
        }

次に Type-Length-Value メッセージが sensor メッセージにデシリアライズされる:

            qt::examples::sensors::Coordinates coord;
            coord.deserialize(&m_serializer, msg.value());
            emit coordinatesUpdated(coord);
            break;

最後に、Type-Length-Value メッセージが変換され、ユーザに表示される:

    ui->latitudeValue->setText(QString::number(coord.latitude(), 'f', 7));
    ui->longitudeValue->setText(QString::number(coord.longitude(), 'f', 7));
    ui->altitudeValue->setText(QString::number(coord.altitude(), 'f', 7));

Note: サンプルを実行する前に、オペレーティングシステムが UDP ポート65500 のバインディングと UDP でのデータ送信を許可していることを確認してください。

サンプルプロジェクト @ code.qt.io

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