使用 MQTT 协议与 IoT 中心通信Communicate with your IoT hub using the MQTT protocol

IoT 中心允许设备通过以下方式与 IoT 中心设备终结点通信:IoT Hub enables devices to communicate with the IoT Hub device endpoints using:

  • 在端口 8883 上使用 MQTT v3.1.1MQTT v3.1.1 on port 8883
  • 在端口 443 上使用基于 WebSocket 的 MQTT v3.1.1。MQTT v3.1.1 over WebSocket on port 443.

IoT 中心不是功能完备的 MQTT 中转站,并未支持 MQTT v3.1.1 标准中指定的所有行为。IoT Hub is not a full-featured MQTT broker and does not support all the behaviors specified in the MQTT v3.1.1 standard. 本文介绍设备如何使用受支持的 MQTT 行为来与 IoT 中心通信。This article describes how devices can use supported MQTT behaviors to communicate with IoT Hub.

备注

本文中提到的某些功能(例如云到设备消息传递、设备孪生、设备管理)仅在 IoT 中心的标准层中提供。Some of the features mentioned in this article, like cloud-to-device messaging, device twins, and device management, are only available in the standard tier of IoT hub. 有关基本和标准 IoT 中心层的详细信息,请参阅如何选择合适的 IoT 中心层For more information about the basic and standard IoT Hub tiers, see How to choose the right IoT Hub tier.

所有通过 IoT 中心进行的设备通信都必须使用 TLS/SSL 来保护。All device communication with IoT Hub must be secured using TLS/SSL. 因此,IoT 中心不支持通过端口 1883 进行的不安全的连接。Therefore, IoT Hub doesn’t support non-secure connections over port 1883.

连接到 IoT 中心Connecting to IoT Hub

设备可以通过以下任意选项使用 MQTT 协议连接到 IoT 中心。A device can use the MQTT protocol to connect to an IoT hub using any of the following options.

许多企业和教育网络环境中都会 MQTT 端口 (8883)。The MQTT port (8883) is blocked in many corporate and educational networking environments. 如果无法在防火墙中打开端口 8883,建议使用基于 Web 套接字的 MQTT。If you can't open port 8883 in your firewall, we recommend using MQTT over Web Sockets. 基于 Web 套接字的 MQTT 通过端口 443 进行通信,该端口在网络环境中几乎始终是打开的。MQTT over Web Sockets communicates over port 443, which is almost always open in networking environments. 若要了解如何在使用 Azure IoT SDK 时指定 MQTT 和基于 Web 套接字的 MQTT 协议,请参阅使用设备 SDKTo learn how to specify the MQTT and MQTT over Web Sockets protocols when using the Azure IoT SDKs, see Using the device SDKs.

使用设备 SDKUsing the device SDKs

支持 MQTT 协议的设备 SDK 可用于 Java、Node.js、C、C# 和 Python。Device SDKs that support the MQTT protocol are available for Java, Node.js, C, C#, and Python. 设备 SDK 使用标准 IoT 中心连接字符串来连接到 IoT 中心。The device SDKs use the standard IoT Hub connection string to establish a connection to an IoT hub. 要使用 MQTT 协议,必须将客户端协议参数设置为 MQTTTo use the MQTT protocol, the client protocol parameter must be set to MQTT. 还可以在客户端协议参数中指定基于 Web 套接字的 MQTT。You can also specify MQTT over Web Sockets in the client protocol parameter. 默认情况下,设备 SDK 在 CleanSession 标志设置为 0 的情况下连接到 IoT 中心,并使用 QoS 1 来与 IoT 中心交换消息。By default, the device SDKs connect to an IoT Hub with the CleanSession flag set to 0 and use QoS 1 for message exchange with the IoT hub. 虽然可以配置 QoS 0 以加快消息交换速度,但你应该注意,这种传递不能得到保证或确认。While it's possible to configure QoS 0 for faster message exchange, you should note that the delivery isn't guaranteed nor acknowledged. 出于此原因,QoS 0 通常称为“用后即焚”。For this reason, QoS 0 is often referred as "fire and forget".

当设备连接到 IoT 中心时,设备 SDK 会提供方法,让设备与 IoT 中心交换消息。When a device is connected to an IoT hub, the device SDKs provide methods that enable the device to exchange messages with an IoT hub.

下表包含了每种受支持语言的代码示例链接,并指定了通过 MQTT 或基于 Web 套接字的 MQTT 协议建立到 IoT 中心的连接时要使用的参数。The following table contains links to code samples for each supported language and specifies the parameter to use to establish a connection to IoT Hub using the MQTT or the MQTT over Web Sockets protocol.

语言Language MQTT 协议参数MQTT protocol parameter 基于 Web 套接字的 MQTT 协议参数MQTT over Web Sockets protocol parameter
Node.jsNode.js azure-iot-device-mqtt.Mqttazure-iot-device-mqtt.Mqtt azure-iot-device-mqtt.MqttWsazure-iot-device-mqtt.MqttWs
JavaJava IotHubClientProtocol.MQTTIotHubClientProtocol.MQTT IotHubClientProtocol.MQTT_WSIotHubClientProtocol.MQTT_WS
CC MQTT_ProtocolMQTT_Protocol MQTT_WebSocket_ProtocolMQTT_WebSocket_Protocol
C#C# TransportType.MqttTransportType.Mqtt 如果 MQTT 失败,TransportType.Mqtt 将退回到基于 Web 套接字的 MQTT。TransportType.Mqtt falls back to MQTT over Web Sockets if MQTT fails. 若仅指定基于 Web 套接字的 MQTT,请使用 TransportType.Mqtt_WebSocket_OnlyTo specify MQTT over Web Sockets only, use TransportType.Mqtt_WebSocket_Only
PythonPython 默认支持 MQTTSupports MQTT by default 在调用中添加 websockets=True 来创建客户端Add websockets=True in the call to create the client

以下片段展示如何在使用 Azure IoT Node.js SDK 时指定基于 Web 套接字的 MQTT 协议:The following fragment shows how to specify the MQTT over Web Sockets protocol when using the Azure IoT Node.js SDK:

var Client = require('azure-iot-device').Client;
var Protocol = require('azure-iot-device-mqtt').MqttWs;
var client = Client.fromConnectionString(deviceConnectionString, Protocol);

以下片段展示如何在使用 Azure IoT Python SDK 时指定基于 Web 套接字的 MQTT 协议:The following fragment shows how to specify the MQTT over Web Sockets protocol when using the Azure IoT Python SDK:

from azure.iot.device.aio import IoTHubDeviceClient
device_client = IoTHubDeviceClient.create_from_connection_string(deviceConnectionString, websockets=True)

默认的 keep-alive 超时Default keep-alive timeout

为了确保客户端/IoT 中心连接保持活动状态,服务和客户端会定期向对方发送一个 keep-alive ping。In order to ensure a client/IoT Hub connection stays alive, both the service and the client regularly send a keep-alive ping to each other. 使用 IoT SDK 的客户端按下表中定义的时间间隔发送 keep-alive:The client using IoT SDK sends a keep-alive at the interval defined in this table below:

语言Language 默认的 keep-alive 时间间隔Default keep-alive interval 可配置性Configurable
Node.jsNode.js 180 秒180 seconds No
JavaJava 230 秒230 seconds No
CC 240 秒240 seconds Yes
C#C# 300 秒300 seconds Yes
PythonPython 60 秒60 seconds No

按照 MQTT 规范,IoT 中心的 keep-alive ping 时间间隔是客户端 keep-alive 值的 1.5 倍。Following MQTT spec, IoT Hub's keep-alive ping interval is 1.5 times the client keep-alive value. 但是,IoT 中心将服务器端最大超时限制为 29.45 分钟(1767 秒),因为所有 Azure 服务都绑定到了 Azure 负载均衡器 TCP 空闲超时(29.45 分钟)。However, IoT Hub limits the maximum server-side timeout to 29.45 minutes (1767 seconds) because all Azure services are bound to the Azure load balancer TCP idle timeout, which is 29.45 minutes.

例如,使用 Java SDK 的设备会发送 keep-alive ping,然后失去网络连接。For example, a device using the Java SDK sends the keep-alive ping then loses network connectivity. 230 秒后,设备会由于处于脱机状态而错过 keep-alive ping。230 seconds later, the device misses the keep-alive ping because it's offline. 但是,IoT 中心不会立即关闭连接 - 它会再等待 (230 * 1.5) - 230 = 115 秒,然后再断开设备的连接,并显示错误 404104 DeviceConnectionClosedRemotelyHowever, IoT Hub doesn't close the connection immediately - it waits another (230 * 1.5) - 230 = 115 seconds before disconnecting the device with the error 404104 DeviceConnectionClosedRemotely.

可设置的客户端最大 keep-alive 值为 1767 / 1.5 = 1177 秒。The maximum client keep-alive value you can set is 1767 / 1.5 = 1177 seconds. 任何流量都将重置 keep-alive。Any traffic will reset the keep-alive. 例如,成功的 SAS 令牌刷新会重置 keep-alive。For example, a successful SAS token refresh resets the keep-alive.

将设备应用从 AMQP 迁移到 MQTTMigrating a device app from AMQP to MQTT

如果使用设备 SDK,则从使用 AMQP 切换到 MQTT 需要在客户端初始化中更改协议参数,如前面所述。If you are using the device SDKs, switching from using AMQP to MQTT requires changing the protocol parameter in the client initialization as stated previously.

执行此操作时,请确保检查下列各项:When doing so, make sure to check the following items:

  • AMQP 针对许多条件返回错误,而 MQTT 会终止连接。AMQP returns errors for many conditions, while MQTT terminates the connection. 因此异常处理逻辑可能需要进行一些更改。As a result your exception handling logic might require some changes.

  • MQTT 在接收云到设备消息时不支持拒绝操作。MQTT does not support the reject operations when receiving cloud-to-device messages. 如果后端应用需要接收来自设备应用的响应,请考虑使用直接方法If your back-end app needs to receive a response from the device app, consider using direct methods.

  • Python SDK 不支持 AMQPAMQP is not supported in the Python SDK

直接使用 MQTT 协议(作为设备)Using the MQTT protocol directly (as a device)

如果设备无法使用设备 SDK,仍可使用端口 8883 上的 MQTT 协议连接到公共设备终结点。If a device cannot use the device SDKs, it can still connect to the public device endpoints using the MQTT protocol on port 8883. CONNECT 数据包中,设备应使用以下值:In the CONNECT packet the device should use the following values:

  • ClientId 字段使用 deviceIdFor the ClientId field, use the deviceId.

  • “用户名”字段使用 {iothubhostname}/{device_id}/?api-version=2018-06-30,其中 {iothubhostname} 是 IoT 中心的完整 CName。For the Username field, use {iothubhostname}/{device_id}/?api-version=2018-06-30, where {iothubhostname} is the full CName of the IoT hub.

    例如,如果 IoT 中心的名称为 contoso.azure-devices.cn,且设备的名称为 MyDevice01,则完整“用户名”字段应包含:For example, if the name of your IoT hub is contoso.azure-devices.cn and if the name of your device is MyDevice01, the full Username field should contain:

    contoso.azure-devices.cn/MyDevice01/?api-version=2018-06-30

  • “密码” 字段使用 SAS 令牌。For the Password field, use a SAS token. 对于 HTTPS 和 AMQP 协议,SAS 令牌的格式是相同的:The format of the SAS token is the same as for both the HTTPS and AMQP protocols:

    SharedAccessSignature sig={signature-string}&se={expiry}&sr={URL-encoded-resourceURI}

    备注

    如果使用 X.509 证书身份验证,则不需要使用 SAS 令牌密码。If you use X.509 certificate authentication, SAS token passwords are not required. 有关详细信息,请参阅在 Azure IoT 中心设置 X.509 安全性并按照以下代码说明进行操作。For more information, see Set up X.509 security in your Azure IoT Hub and follow code instructions below.

    有关如何生成 SAS 令牌的详细信息,请参阅使用 IoT 中心安全令牌的设备部分。For more information about how to generate SAS tokens, see the device section of Using IoT Hub security tokens.

    测试时,也可以使用跨平台的适用于 Visual Studio Code 的 Azure IoT Tools 或 CLI 扩展命令 az iot hub generate-sas-token 快速生成可以复制并粘贴到自己的代码中的 SAS 令牌:When testing, you can also use the cross-platform Azure IoT Tools for Visual Studio Code or the CLI extension command az iot hub generate-sas-token to quickly generate a SAS token that you can copy and paste into your own code:

对于 Azure IoT ToolsFor Azure IoT Tools

  1. 展开 Visual Studio Code 左下角的“AZURE IOT 中心设备”选项卡。Expand the AZURE IOT HUB DEVICES tab in the bottom left corner of Visual Studio Code.
  2. 右键单击设备,然后选择“为设备生成 SAS 令牌”。Right-click your device and select Generate SAS Token for Device.
  3. 设置“到期时间”,然后按 Enter。Set expiration time and press 'Enter'.
  4. 将创建 SAS 令牌并将其复制到剪贴板。The SAS token is created and copied to clipboard.

所生成的 SAS 令牌具有以下结构:The SAS token that's generated has the following structure:

HostName={your hub name}.azure-devices.net;DeviceId=javadevice;SharedAccessSignature=SharedAccessSignature sr={your hub name}.azure-devices.net%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14&sig=vSgHBMUG.....Ntg%3d&se=1456481802

 <span data-ttu-id="16cfe-206">此令牌中要用作“**密码**”字段以便使用 MQTT 进行连接的部分是:`SharedAccessSignature sr={your hub name}.azure-devices.cn%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14&sig=vSgHBMUG.....Ntg%3d&se=1456481802`。</span><span class="sxs-lookup"><span data-stu-id="16cfe-206">The part of this token to use as the **Password** field to connect using MQTT is: `SharedAccessSignature sr={your hub name}.azure-devices.cn%2Fdevices%2FMyDevice01%2Fapi-version%3D2016-11-14&sig=vSgHBMUG.....Ntg%3d&se=1456481802`.</span></span>

对于 MQTT 连接和断开连接数据包,IoT 中心会在操作监视通道上发出事件。For MQTT connect and disconnect packets, IoT Hub issues an event on the Operations Monitoring channel. 此事件包含的其他信息有助于排查连接问题。This event has additional information that can help you to troubleshoot connectivity issues.

设备应用可以在 CONNECT 数据包中指定 Will 消息 。The device app can specify a Will message in the CONNECT packet. 设备应用应该使用 devices/{device_id}/messages/events/devices/{device_id}/messages/events/{property_bag} 作为 Will 主题名称,用于定义要作为遥测消息转发的 Will 消息 。The device app should use devices/{device_id}/messages/events/ or devices/{device_id}/messages/events/{property_bag} as the Will topic name to define Will messages to be forwarded as a telemetry message. 在此情况下,如果关闭网络连接,但之前未从设备中接收到 DISCONNECT 数据包,则 IoT 中心将 CONNECT 数据包中提供的 Will 消息发送到遥测通道 。In this case, if the network connection is closed, but a DISCONNECT packet was not previously received from the device, then IoT Hub sends the Will message supplied in the CONNECT packet to the telemetry channel. 遥测通道可以是默认事件终结点或由 IoT 中心路由定义的自定义终结点。The telemetry channel can be either the default Events endpoint or a custom endpoint defined by IoT Hub routing. 消息具有 iothub-MessageType 属性,其中包含分配给它的 Will 的值 。The message has the iothub-MessageType property with a value of Will assigned to it.

在不使用 Azure IoT C SDK 的情况下使用 MQTT 的 C 代码示例An example of C code using MQTT without Azure IoT C SDK

存储库中有几个 C/C++ 演示项目,演示如何在不使用 Azure IoT C SDK 的情况下通过 IoT 中心发送遥测消息并接收事件。In this repository, you'll find a couple of C/C++ demo projects showing how to send telemetry messages, receive events with an IoT hub without using the Azure IoT C SDK.

这些示例使用 Eclipse Mosquitto 库将消息发送到在 IoT 中心实现的 MQTT 中转站。These samples use the Eclipse Mosquitto library to send message to the MQTT Broker implemented in the IoT hub.

此存储库包含:This repository contains:

对于 Windows:For Windows:

• TelemetryMQTTWin32:包含将遥测消息发送到在 Windows 计算机上生成并运行的 Azure IoT 中心的代码。• TelemetryMQTTWin32: contains code to send a telemetry message to an Azure IoT hub, built and run on a Windows machine.

• SubscribeMQTTWin32:包含用于在 Windows 计算机上订阅给定 IoT 中心事件的代码。• SubscribeMQTTWin32: contains code to subscribe to events of a given IoT hub on a Windows machine.

• DeviceTwinMQTTWin32:包含用于在 Windows 计算机上查询和订阅 Azure IoT 中心内设备的设备孪生事件的代码。• DeviceTwinMQTTWin32: contains code to query and subscribe to the device twin events of a device in the Azure IoT hub on a Windows machine.

对于 Linux:For Linux:

• MQTTLinux:包含要在 Linux 上运行的代码和生成脚本(到目前为止,WSL、Ubuntu 和 Raspbian 已经过测试)。• MQTTLinux: contains code and build script to run on Linux (WSL, Ubuntu and Raspbian have been tested so far).

• LinuxConsoleVS2019:包含相同的代码,但在针对 WSL(Windows Linux 子系统)的 VS2019 项目中。• LinuxConsoleVS2019: contains the same code but in a VS2019 project targeting WSL (Windows Linux sub system). 通过此项目,你可以从 Visual Studio 逐步调试在 Linux 上运行的代码。This project allows you to debug the code running on Linux step by step from Visual Studio.

对于 mosquitto_pub:For mosquitto_pub:

• 此文件夹包含与 Mosquitto.org 提供的 mosquitto_pub 实用工具一起使用的两个示例命令。• This folder contains two samples commands used with mosquitto_pub utility tool provided by Mosquitto.org.

Mosquitto_sendmessage:用于将简单文本消息发送到充当设备的 Azure IoT 中心。Mosquitto_sendmessage: to send a simple text message to an Azure IoT hub acting as a device.

Mosquitto_subscribe:用于查看 Azure IoT 中心发生的事件。Mosquitto_subscribe: to see events occurring in an Azure IoT hub.

直接使用 MQTT 协议(作为模块)Using the MQTT protocol directly (as a module)

通过 MQTT 并使用模块标识连接到 IoT 中心的操作与设备类似(如上面所述),但需要:Connecting to IoT Hub over MQTT using a module identity is similar to the device (described above) but you need to use the following:

  • 将客户端 ID 设置为 {device_id}/{module_id}Set the client id to {device_id}/{module_id}.
  • 如果使用用户名和密码进行身份验证,请将用户名设置为 <hubname>.azure-devices.cn/{device_id}/{module_id}/?api-version=2018-06-30,并使用与模块标识关联的 SAS 令牌作为密码。If authenticating with username and password, set the username to <hubname>.azure-devices.cn/{device_id}/{module_id}/?api-version=2018-06-30 and use the SAS token associated with the module identity as your password.
  • 使用 devices/{device_id}/modules/{module_id}/messages/events/ 作为主题,用于发布遥测。Use devices/{device_id}/modules/{module_id}/messages/events/ as topic for publishing telemetry.
  • 使用 devices/{device_id}/modules/{module_id}/messages/events/ 作为 WILL 主题。Use devices/{device_id}/modules/{module_id}/messages/events/ as WILL topic.
  • 模块和设备的孪生 GET 和 PATCH 主题是相同的。The twin GET and PATCH topics are identical for modules and devices.
  • 模块和设备的孪生状态主题是相同的。The twin status topic is identical for modules and devices.

TLS/SSL 配置TLS/SSL configuration

若要直接使用 MQTT 协议,客户端必须通过 TLS/SSL 连接。To use the MQTT protocol directly, your client must connect over TLS/SSL. 尝试跳过此步骤失败并显示连接错误。Attempts to skip this step fail with connection errors.

若要建立 TLS 连接,可能需要下载并引用 DigiCert Baltimore 根证书。In order to establish a TLS connection, you may need to download and reference the DigiCert Baltimore Root Certificate. 此证书是 Azure 用来保护连接安全的。This certificate is the one that Azure uses to secure the connection. 可以在 Azure-iot-sdk-c 存储库中找到此证书。You can find this certificate in the Azure-iot-sdk-c repository. 可以在 Digicert 网站上找到有关这些证书的详细信息。More information about these certificates can be found on Digicert's website.

一个说明如何使用 Eclipse Foundation 提供的 Python 版本的 Paho MQTT 库实现此功能的示例可能如下所示。An example of how to implement this using the Python version of the Paho MQTT library by the Eclipse Foundation might look like the following.

首先,从命令行环境安装 Paho 库:First, install the Paho library from your command-line environment:

pip install paho-mqtt

然后,在 Python 脚本中实现客户端。Then, implement the client in a Python script. 替换这些占位符,如下所示:Replace the placeholders as follows:

  • <local path to digicert.cer> 是包含 DigiCert Baltimore Root 证书的本地文件的路径。<local path to digicert.cer> is the path to a local file that contains the DigiCert Baltimore Root certificate. 创建此文件时,可以在用于 C 的 Azure IoT SDK 中复制 certs.c 中的证书信息。包括 -----BEGIN CERTIFICATE----- 行和 -----END CERTIFICATE----- 行,删除每行开头和结尾的 " 标记,并删除每行结尾的 \r\n 字符。You can create this file by copying the certificate information from certs.c in the Azure IoT SDK for C. Include the lines -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----, remove the " marks at the beginning and end of every line, and remove the \r\n characters at the end of every line.
  • <device id from device registry> 是添加到 IoT 中心的设备的 ID。<device id from device registry> is the ID of a device you added to your IoT hub.
  • <generated SAS token> 是已创建设备的 SAS 令牌,如本文前面所述。<generated SAS token> is a SAS token for the device created as described previously in this article.
  • <iot hub name>:IoT 中心的名称。<iot hub name> the name of your IoT hub.
from paho.mqtt import client as mqtt
import ssl

path_to_root_cert = "<local path to digicert.cer file>"
device_id = "<device id from device registry>"
sas_token = "<generated SAS token>"
iot_hub_name = "<iot hub name>"

def on_connect(client, userdata, flags, rc):
  print ("Device connected with result code: " + str(rc))
def on_disconnect(client, userdata, rc):
  print ("Device disconnected with result code: " + str(rc))
def on_publish(client, userdata, mid):
  print ("Device sent message")

client = mqtt.Client(client_id=device_id, protocol=mqtt.MQTTv311)

client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_publish = on_publish

client.username_pw_set(username=iot_hub_name+".azure-devices.cn/" +
                       device_id + "/?api-version=2018-06-30", password=sas_token)

client.tls_set(ca_certs=path_to_root_cert, certfile=None, keyfile=None,
               cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
client.tls_insecure_set(False)

client.connect(iot_hub_name+".azure-devices.cn", port=8883)

client.publish("devices/" + device_id + "/messages/events/", "{id=123}", qos=1)
client.loop_forever()

若要使用设备证书进行身份验证,请使用以下更改更新上面的代码片段(请参阅如何获取 X.509 CA 证书,了解如何准备进行基于证书的身份验证):To authenticate using a device certificate, update the code snippet above with the following changes (see How to get an X.509 CA certificate on how to prepare for certificate-based authentication):

# Create the client as before
# ...

# Set the username but not the password on your client
client.username_pw_set(username=iot_hub_name+".azure-devices.cn/" +
                       device_id + "/?api-version=2018-06-30", password=None)

# Set the certificate and key paths on your client
cert_file = "<local path to your certificate file>"
key_file = "<local path to your device key file>"
client.tls_set(ca_certs=path_to_root_cert, certfile=cert_file, keyfile=key_file,
               cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)

# Connect as before
client.connect(iot_hub_name+".azure-devices.cn", port=8883)

发送“设备到云”消息Sending device-to-cloud messages

成功建立连接后,设备可以使用 devices/{device_id}/messages/events/devices/{device_id}/messages/events/{property_bag} 作为主题名称将消息发送到 IoT 中心。After making a successful connection, a device can send messages to IoT Hub using devices/{device_id}/messages/events/ or devices/{device_id}/messages/events/{property_bag} as a Topic Name. {property_bag} 元素可让设备使用 URL 编码格式发送包含其他属性的消息。The {property_bag} element enables the device to send messages with additional properties in a url-encoded format. 例如:For example:

RFC 2396-encoded(<PropertyName1>)=RFC 2396-encoded(<PropertyValue1>)&RFC 2396-encoded(<PropertyName2>)=RFC 2396-encoded(<PropertyValue2>)…

备注

{property_bag} 元素使用与 HTTPS 协议中的查询字符串相同的编码。This {property_bag} element uses the same encoding as query strings in the HTTPS protocol.

下面列出了 IoT 中心特定于实现的行为:The following is a list of IoT Hub implementation-specific behaviors:

  • IoT 中心不支持 QoS 2 消息。IoT Hub does not support QoS 2 messages. 如果设备应用使用 QoS 2 发布消息,IoT 中心将断开网络连接。If a device app publishes a message with QoS 2, IoT Hub closes the network connection.
  • IoT 中心不会保存 Retain 消息。IoT Hub does not persist Retain messages. 如果设备在 RETAIN 标志设置为 1 的情况下发送消息,则 IoT 中心会在消息中添加 x-opt-retain 应用程序属性。If a device sends a message with the RETAIN flag set to 1, IoT Hub adds the x-opt-retain application property to the message. 在此情况下,IoT 中心不会存储保留消息,而将其传递到后端应用。In this case, instead of persisting the retain message, IoT Hub passes it to the backend app.
  • IoT 中心仅支持每个设备一个活动 MQTT 连接。IoT Hub only supports one active MQTT connection per device. 代表相同设备 ID 的任何新 MQTT 连接都会导致 IoT 中心删除现有连接。Any new MQTT connection on behalf of the same device ID causes IoT Hub to drop the existing connection.

有关详细信息,请参阅消息传送开发人员指南For more information, see Messaging developer's guide.

接收“云到设备”消息Receiving cloud-to-device messages

若要从 IoT 中心接收消息,设备应使用 devices/{device_id}/messages/devicebound/# 作为主题筛选器来进行订阅。To receive messages from IoT Hub, a device should subscribe using devices/{device_id}/messages/devicebound/# as a Topic Filter. 主题筛选器中的多级通配符 # 仅用于允许设备接收主题名称中的其他属性。The multi-level wildcard # in the Topic Filter is used only to allow the device to receive additional properties in the topic name. IoT 中心不允许使用 #? 通配符筛选子主题。IoT Hub does not allow the usage of the # or ? wildcards for filtering of subtopics. 由于 IoT 中心不是常规用途的发布-订阅消息传送中转站,因此它仅支持存档的主题名称和主题筛选器。Since IoT Hub is not a general-purpose pub-sub messaging broker, it only supports the documented topic names and topic filters.

在设备成功订阅 devices/{device_id}/messages/devicebound/# 主题筛选器表示的设备特定终结点前,不会从 IoT 中心收到任何消息。The device does not receive any messages from IoT Hub, until it has successfully subscribed to its device-specific endpoint, represented by the devices/{device_id}/messages/devicebound/# topic filter. 建立订阅后,设备会接收建立订阅后发送给它的云到设备消息。After a subscription has been established, the device receives cloud-to-device messages that were sent to it after the time of the subscription. 如果设备在 CleanSession 标志设置为 0 的情况下进行连接,则订阅在经历不同的会话后仍然持久存在。If the device connects with CleanSession flag set to 0, the subscription is persisted across different sessions. 在此情况下,下次使用 CleanSession 0 进行连接时,设备会收到断开连接时发送给它的未处理消息。In this case, the next time the device connects with CleanSession 0 it receives any outstanding messages sent to it while disconnected. 但是,如果设备使用设置为 1 的 CleanSession 标志,在订阅其设备终结点前,它不会从 IoT 中心收到任何消息。If the device uses CleanSession flag set to 1 though, it does not receive any messages from IoT Hub until it subscribes to its device-endpoint.

如有消息属性,IoT 中心会传送包含主题名称 devices/{device_id}/messages/devicebound/devices/{device_id}/messages/devicebound/{property_bag} 的消息。IoT Hub delivers messages with the Topic Name devices/{device_id}/messages/devicebound/, or devices/{device_id}/messages/devicebound/{property_bag} when there are message properties. {property_bag} 包含 URL 编码的消息属性键/值对。{property_bag} contains url-encoded key/value pairs of message properties. 属性包中只包含应用程序属性和用户可设置的系统属性(例如 messageIdcorrelationId)。Only application properties and user-settable system properties (such as messageId or correlationId) are included in the property bag. 系统属性名称具有前缀 $ ,但应用程序属性使用没有前缀的原始属性名称。System property names have the prefix $, application properties use the original property name with no prefix. 有关属性包格式的其他详细信息,请参阅发送设备到云的消息For additional details about the format of the property bag, see Sending device-to-cloud messages.

在云到设备消息中,属性包中的值的表示形式如下表所示:In cloud-to-device messages, values in the property bag are represented as in the following table:

属性值Property value 表示形式Representation 说明Description
null key 属性包中只显示密钥Only the key appears in the property bag
空字符串empty string key= 密钥后跟一个等号,无值The key followed by an equal sign with no value
不可为 null、非空值non-null, non-empty value key=value 密钥后跟一个等号和值The key followed by an equal sign and the value

以下示例显示包含三个应用程序属性的属性包:值为 null 的 prop1、为空字符串 ("") 的 prop2 和值为“string”的 prop3 。The following example shows a property bag that contains three application properties: prop1 with a value of null; prop2, an empty string (""); and prop3 with a value of "a string".

/?prop1&prop2=&prop3=a%20string

当设备应用使用 QoS 2 订阅主题时,IoT 中心会在 SUBACK 包中授予最高 QoS 级别 1。When a device app subscribes to a topic with QoS 2, IoT Hub grants maximum QoS level 1 in the SUBACK packet. 之后,IoT 中心会使用 QoS 1 将消息传送到设备。After that, IoT Hub delivers messages to the device using QoS 1.

检索设备克隆的属性Retrieving a device twin's properties

首先,设备订阅 $iothub/twin/res/#,接收操作的响应。First, a device subscribes to $iothub/twin/res/#, to receive the operation's responses. 然后,它向主题 $iothub/twin/GET/?$rid={request id} 发送一条空消息,其中包含 request id 的填充值。服务随后会发送一条响应消息,其中包含关于主题 $iothub/twin/res/{status}/?$rid={request id} 的设备孪生数据,并且使用与请求相同的“request id”。Then, it sends an empty message to topic $iothub/twin/GET/?$rid={request id}, with a populated value for request id. The service then sends a response message containing the device twin data on topic $iothub/twin/res/{status}/?$rid={request id}, using the same request id as the request.

Request ID 可以是消息属性值的任何有效值(如 IoT 中心消息传送开发人员指南中所述),且需要验证确保状态是整数。Request ID can be any valid value for a message property value, as per IoT Hub messaging developer's guide, and status is validated as an integer.

响应正文包含设备孪生的 properties 节,如以下响应示例所示:The response body contains the properties section of the device twin, as shown in the following response example:

{
    "desired": {
        "telemetrySendFrequency": "5m",
        "$version": 12
    },
    "reported": {
        "telemetrySendFrequency": "5m",
        "batteryLevel": 55,
        "$version": 123
    }
}

可能的状态代码为:The possible status codes are:

状态Status 说明Description
200200 SuccessSuccess
429429 请求过多(受限),如 IoT 中心限制中所述Too many requests (throttled), as per IoT Hub throttling
55 服务器错误Server errors

有关详细信息,请参阅设备孪生开发人员指南For more information, see Device twins developer's guide.

更新设备孪生的报告属性Update device twin's reported properties

若要更新已报告的属性,设备通过指定的 MQTT 主题上的发布向 IoT 中心发出请求。To update reported properties, the device issues a request to IoT Hub via a publication over a designated MQTT topic. 处理完请求后,IoT 中心会通过发布到其他主题来响应更新操作的成功或失败状态。After processing the request, IoT Hub responds the success or failure status of the update operation via a publication to another topic. 设备可以订阅此主题,以便通知它有关其孪生更新请求的结果。This topic can be subscribed by the device in order to notify it about the result of its twin update request. 为了在 MQTT 中实现此类型的请求/响应交互,我们利用了设备在其更新请求中最初提供的请求 ID ($rid) 的概念。To implement this type of request/response interaction in MQTT, we leverage the notion of request ID ($rid) provided initially by the device in its update request. 此请求 ID 也包含在 IoT 中心的响应中,以允许设备将响应与其特定的早期请求相关联。This request ID is also included in the response from IoT Hub to allow the device to correlate the response to its particular earlier request.

以下序列描述了设备如何在 IoT 中心中更新设备孪生中报告的属性:The following sequence describes how a device updates the reported properties in the device twin in IoT Hub:

  1. 设备必须首先订阅 $iothub/twin/res/# 主题才能从 IoT 中心接收操作的响应。A device must first subscribe to the $iothub/twin/res/# topic to receive the operation's responses from IoT Hub.

  2. 设备发送一条消息,其中包含 $iothub/twin/PATCH/properties/reported/?$rid={request id} 主题的设备孪生更新。A device sends a message that contains the device twin update to the $iothub/twin/PATCH/properties/reported/?$rid={request id} topic. 该消息包含 请求 ID 值。This message includes a request id value.

  3. 然后,服务发送一条响应消息,其中包含主题 $iothub/twin/res/{status}/?$rid={request id} 的已报告属性集合的全新 ETag 值。The service then sends a response message that contains the new ETag value for the reported properties collection on topic $iothub/twin/res/{status}/?$rid={request id}. 此响应消息使用与请求相同的请求 IDThis response message uses the same request id as the request.

请求消息正文包含 JSON 文档,该文档包含已报告属性的新值。The request message body contains a JSON document, that contains new values for reported properties. JSON 文档中的每个成员都会在设备孪生文档中更新或添加相应成员。Each member in the JSON document updates or add the corresponding member in the device twin’s document. 设置为 null的成员会从包含的对象中删除成员。A member set to null, deletes the member from the containing object. 例如:For example:

{
    "telemetrySendFrequency": "35m",
    "batteryLevel": 60
}

可能的状态代码为:The possible status codes are:

状态Status 说明Description
204204 成功(不返回任何内容)Success (no content is returned)
400400 错误的请求。Bad Request. 格式不正确的 JSONMalformed JSON
429429 请求过多(受限),如 IoT 中心限制中所述Too many requests (throttled), as per IoT Hub throttling
55 服务器错误Server errors

下面的 python 代码片段演示了 MQTT 上孪生已报告属性更新过程(使用 Paho MQTT 客户端):The python code snippet below, demonstrates the twin reported properties update process over MQTT (using Paho MQTT client):

from paho.mqtt import client as mqtt

# authenticate the client with IoT Hub (not shown here)

client.subscribe("$iothub/twin/res/#")
rid = "1"
twin_reported_property_patch = "{\"firmware_version\": \"v1.1\"}"
client.publish("$iothub/twin/PATCH/properties/reported/?$rid=" + rid, twin_reported_property_patch, qos=0)

上述孪生已报告属性更新操作成功后,来自 IoT 中心的发布消息将具有以下主题:$iothub/twin/res/204/?$rid=1&$version=6,其中 204 是表示成功的状态代码,$rid=1 对应于代码中设备提供的请求 ID,$version 对应于更新后设备孪生已报告属性部分的版本。Upon success of twin reported properties update operation above, the publication message from IoT Hub will have the following topic: $iothub/twin/res/204/?$rid=1&$version=6, where 204 is the status code indicating success, $rid=1 corresponds to the request ID provided by the device in the code, and $version corresponds to the version of reported properties section of device twins after the update.

有关详细信息,请参阅设备孪生开发人员指南For more information, see Device twins developer's guide.

接收所需属性更新通知Receiving desired properties update notifications

设备连接时,IoT 中心会向主题 $iothub/twin/PATCH/properties/desired/?$version={new version} 发送通知,内附解决方案后端执行的更新内容。When a device is connected, IoT Hub sends notifications to the topic $iothub/twin/PATCH/properties/desired/?$version={new version}, which contain the content of the update performed by the solution back end. 例如:For example:

{
    "telemetrySendFrequency": "5m",
    "route": null,
    "$version": 8
}

对于属性更新,null 值表示正在删除 JSON 对象成员。As for property updates, null values mean that the JSON object member is being deleted. 另请注意,$version 指示孪生的所需属性部分的新版本。Also, note that $version indicates the new version of the desired properties section of the twin.

重要

IoT 中心仅在连接设备时才会生成更改通知。IoT Hub generates change notifications only when devices are connected. 请确保实现设备重新连接流,让 IoT 中心和设备应用之间的所需属性保持同步。Make sure to implement the device reconnection flow to keep the desired properties synchronized between IoT Hub and the device app.

有关详细信息,请参阅设备孪生开发人员指南For more information, see Device twins developer's guide.

响应直接方法Respond to a direct method

首先,设备需要订阅 $iothub/methods/POST/#First, a device has to subscribe to $iothub/methods/POST/#. IoT 中心向主题 $iothub/methods/POST/{method name}/?$rid={request id} 发送方法请求,其中包含有效的 JSON 或空正文。IoT Hub sends method requests to the topic $iothub/methods/POST/{method name}/?$rid={request id}, with either a valid JSON or an empty body.

进行响应时,设备向主题 $iothub/methods/res/{status}/?$rid={request id} 发送带有有效 JSON 或空正文的消息。To respond, the device sends a message with a valid JSON or empty body to the topic $iothub/methods/res/{status}/?$rid={request id}. 在此消息中,request ID 必须与请求消息中的相符,status 必须为整数。In this message, the request ID must match the one in the request message, and status must be an integer.

有关详细信息,请参阅直接方法开发人员指南For more information, see Direct method developer's guide.

其他注意事项Additional considerations

最后要考虑的是,若需在云端自定义 MQTT 协议行为,应参阅 Azure IoT 协议网关As a final consideration, if you need to customize the MQTT protocol behavior on the cloud side, you should review the Azure IoT protocol gateway. 可以通过本软件部署高性能自定义协议网关,该网关直接与 IoT 中心接合。This software enables you to deploy a high-performance custom protocol gateway that interfaces directly with IoT Hub. Azure IoT 协议网关可让你自定义设备协议,以适应要重建的 MQTT 部署或其他自定义协议。The Azure IoT protocol gateway enables you to customize the device protocol to accommodate brownfield MQTT deployments or other custom protocols. 但是,这种方法要求运行并使用自定义协议网关。This approach does require, however, that you run and operate a custom protocol gateway.

后续步骤Next steps

若要了解有关 MQTT 协议的详细信息,请参阅 MQTT 文档To learn more about the MQTT protocol, see the MQTT documentation.

若要深入了解如何规划 IoT 中心部署,请参阅:To learn more about planning your IoT Hub deployment, see:

若要进一步探索 IoT 中心的功能,请参阅:To further explore the capabilities of IoT Hub, see: