传感器

“传感器”示例演示了两个应用程序如何通过 UDP 套接字发送 Protobuf 消息来实现通信。

“传感器”示例由以下组件构成:

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

第二个 .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 字段中的数据将从字符串格式转换为消息字段特有的格式,例如,Coordinates消息的字段将转换为double类型:

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

客户端对接收到的数据报执行反向操作。首先,从数据报数据中反序列化出“类型-长度-值”消息:

       const autodatagram=m_client.receiveDatagram();
        qt::examples::Qt 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;
        }

随后,将“类型-长度-值”消息反序列化为传感器消息:

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

最后,将其转换并显示给用户:

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

注意:在 运行示例之前 ,请确保您的操作系统允许绑定 UDP 端口65500 并通过 UDP 发送数据。

示例项目 @ code.qt.io

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