下面显示的是英文原文。
Qos
Qos picks at most once, at least once or exactly once; a delivery arrives at the lower of the publisher's and the subscription's level.
A subscription names its level with qos(..) on MqttTopic or MqttFilter.
The default is Qos::AtLeastOnce.
| Level | QoS | What the protocol does |
|---|---|---|
AtMostOnce | 0 | sends the message once, with no acknowledgement; a message lost on the way is gone |
AtLeastOnce | 1 | resends until the receiver answers PUBACK; a message may arrive twice |
ExactlyOnce | 2 | a four-packet handshake, so the message arrives once |
The server sends each message at the lower of two levels: the one its publisher sent it at and the one the subscription asked for.
So a QoS 2 subscription receives a QoS 0 publish at QoS 0.
A delivery at QoS 1 or 2 is acknowledged when the handler settles it.
A delivery at QoS 0 has no acknowledgement packet, so settling it reports AckError::Unsupported.
The level a publish is sent at is a setting of the publish policy.
Example
Telemetry read at most once, because the next reading replaces a lost one, and valve commands read exactly once.
- Macros
- Manual
/// A device reports every few seconds, so a lost reading costs nothing: at most once.
#[subscriber(MqttFilter::new("devices/+/telemetry").qos(Qos::AtMostOnce))]
async fn sample(telemetry: &Telemetry) -> HandlerOutcome {
tracing::info!(device = %telemetry.device, telemetry.temperature, "reading sampled");
HandlerOutcome::ack()
}
/// A valve command must run once and never twice: exactly once.
#[subscriber(MqttTopic::new("devices/dev42/commands").qos(Qos::ExactlyOnce))]
async fn execute(command: &Command) -> HandlerOutcome {
tracing::info!(command.id, command.open, "command executed");
HandlerOutcome::ack()
}
/// A device reports every few seconds, so a lost reading costs nothing: at most once.
fn readings() -> MqttFilter {
MqttFilter::new("devices/+/telemetry").qos(Qos::AtMostOnce)
}
/// A valve command must run once and never twice: exactly once.
fn commands() -> MqttTopic {
MqttTopic::new("devices/dev42/commands").qos(Qos::ExactlyOnce)
}