使用 IoT 中心发送云到设备的消息 (Java)

Azure IoT 中心是一项完全托管的服务,有助于在数百万台设备和单个解决方案后端之间实现安全可靠的双向通信。

本文介绍如何:

  • 通过 IoT 中心,将云到设备 (C2D) 消息从解决方案后端发送到单个设备

  • 在设备上接收云到设备的消息

  • 从解决方案后端,请求送达确认,确认收到从 IoT 中心发送到设备的消息(反馈)

注意

本文所述的功能只能用于 IoT 中心的标准层。 有关 IoT 中心基本层和标准/免费层的详细信息,请参阅选择适合你的解决方案的 IoT 中心层

在本文结束时,会运行两个 Java 控制台应用:

  • HandleMessages:适用于 Java 的 Azure IoT SDK 随附的示例设备应用,可连接到 IoT 中心并接收云到设备的消息。

  • SendCloudToDevice:它通过 IoT 中心将云到设备消息发送到设备应用,然后接收其送达确认。

注意

IoT 中心通过 Azure IoT 设备 SDK 对许多设备平台和语言(C、Java、Python 和 JavaScript)提供 SDK 支持

若要详细了解云到设备的消息,请参阅从 IoT 中心发送云到设备的消息

先决条件

  • Azure 订阅。 如果没有 Azure 订阅,可在开始前创建一个试用帐户

  • Azure 订阅中的 IoT 中心。 如果还没有中心,则可以按照创建 IoT 中心中的步骤进行操作。

  • 在 IoT 中心注册的设备。 如果 IoT 中心没有设备,请按照注册设备中的步骤操作。

  • 本教程使用适用于 Java 的 Azure IoT SDK 中的示例代码。

    • 将 SDK 存储库从 GitHub 下载或克隆到开发计算机。
    • 请确保在开发计算机上安装了 Java SE 开发工具包 8。 请确保在“长期支持”下选择“Java 8”以获取 JDK 8 的下载。
  • Maven 3

  • 确保已在防火墙中打开端口 8883。 本文中的设备示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)

获取设备连接字符串

在本文中,你将运行一个模拟设备的示例应用,该应用接收通过 IoT 中心发送的云到设备的消息。 适用于 Java 的 Azure IoT SDK 随附的 HandleMessages 示例应用可连接到 IoT 中心并充当模拟设备。 该示例使用 IoT 中心上已注册设备的主连接字符串。

若要获取注册到 IoT 中心的设备的主连接字符串,请执行以下步骤:

  1. Azure 门户中,选择“资源组”。 选择中心所在的资源组,然后从资源列表中选择中心。

  2. 在 IoT 中心左侧窗格的“设备管理”下,选择“设备”。

  3. 从设备列表中,选择相应的设备。

  4. 复制“主连接字符串”并保存该值。

    屏幕截图显示如何在 Azure 门户中检索注册到 IoT 中心的设备的连接字符串。

在设备应用中接收消息

在本部分中,运行 HandleMessages 示例设备应用以接收通过 IoT 中心发送的 C2D 消息。 打开新命令提示符,并导航到你在其中扩展 Azure IoT Java SDK 的文件夹下的 azure-iot-sdk-java\iothub\device\iot-device-samples\handle-messages 文件夹。 运行以下命令,将 {Your device connection string} 占位符值替换为从 IoT 中心的已注册设备复制的设备连接字符串。

mvn clean package -DskipTests
java -jar ./target/handle-messages-1.0.0-with-deps.jar "{Your device connection string}"

示例设备应用成功启动并连接到 IoT 中心后,其输出如下:

5/22/2023 11:13:18 AM> Press Control+C at any time to quit the sample.
     
Starting...
Beginning setup.
Successfully read input parameters.
Using communication protocol MQTT.
2023-05-23 09:51:06,062 INFO (main) [com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter] - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
2023-05-23 09:51:06,187 DEBUG (main) [com.microsoft.azure.sdk.iot.device.ClientConfiguration] - Device configured to use software based SAS authentication provider
2023-05-23 09:51:06,187 INFO (main) [com.microsoft.azure.sdk.iot.device.transport.ExponentialBackoffWithJitter] - NOTE: A new instance of ExponentialBackoffWithJitter has been created with the following properties. Retry Count: 2147483647, Min Backoff Interval: 100, Max Backoff Interval: 10000, Max Time Between Retries: 100, Fast Retry Enabled: true
2023-05-23 09:51:06,202 DEBUG (main) [com.microsoft.azure.sdk.iot.device.DeviceClient] - Initialized a DeviceClient instance using SDK version 2.1.5
Successfully created an IoT Hub client.
Successfully set message callback.
2023-05-23 09:51:06,205 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.MqttIotHubConnection] - Opening MQTT connection...
2023-05-23 09:51:06,218 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sending MQTT CONNECT packet...
2023-05-23 09:51:07,308 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sent MQTT CONNECT packet was acknowledged
2023-05-23 09:51:07,308 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sending MQTT SUBSCRIBE packet for topic devices/US60536-device/messages/devicebound/#
2023-05-23 09:51:07,388 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.Mqtt] - Sent MQTT SUBSCRIBE packet for topic devices/US60536-device/messages/devicebound/# was acknowledged
2023-05-23 09:51:07,388 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.mqtt.MqttIotHubConnection] - MQTT connection opened successfully
2023-05-23 09:51:07,388 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - The connection to the IoT Hub has been established
2023-05-23 09:51:07,404 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Updating transport status to new status CONNECTED with reason CONNECTION_OK
2023-05-23 09:51:07,404 DEBUG (main) [com.microsoft.azure.sdk.iot.device.DeviceIO] - Starting worker threads
2023-05-23 09:51:07,408 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Invoking connection status callbacks with new status details

CONNECTION STATUS UPDATE: CONNECTED
CONNECTION STATUS REASON: CONNECTION_OK
CONNECTION STATUS THROWABLE: null

The connection was successfully established. Can send messages.
2023-05-23 09:51:07,408 DEBUG (main) [com.microsoft.azure.sdk.iot.device.transport.IotHubTransport] - Client connection opened successfully
2023-05-23 09:51:07,408 INFO (main) [com.microsoft.azure.sdk.iot.device.DeviceClient] - Device client opened successfully
Opened connection to IoT Hub. Messages sent to this device will now be received.
Press any key to exit...

AppMessageCallback 类中的 execute 方法会返回 IotHubMessageResult.COMPLETE。 此状态会通知 IoT 中心,指出已成功处理消息,可以安全地从设备队列中删除该消息了。 无论使用何种协议,设备都会在处理成功完成后返回此值。

使用 AMQP 和 HTTPS,但不使用 MQTT,该设备还可以:

  • 放弃消息,使 IoT 中心将消息保留在设备队列中供将来使用。
  • 拒绝消息,这会永久地从设备队列中删除该消息。

如果发生阻止设备完成、放弃或拒绝消息的情况,IoT 中心会在固定的超时期限过后再次对消息排队以进行传递。 因此,设备应用中的消息处理逻辑必须是幂等的,这样,多次接收相同的消息才会生成相同的结果。

若要获取有关云到设备消息生命周期以及 IoT 中心如何处理云到设备消息的详细信息,请参阅从 IoT 中心发送云到设备的消息

注意

如果使用 HTTPS(而不使用 MQTT 或 AMQP)作为传输,则 DeviceClient 实例不会频繁检查 IoT 中心发来的消息(频率最低为每 25 分钟一次)。 有关 MQTT、AMQP 和 HTTPS 支持之间的差异的详细信息,请参阅云到设备通信指南选择通信协议

获取 IoT 中心连接字符串

本文中,你将创建一个后端服务,用于通过 IoT 中心发送云到设备的消息。 若要发送云到设备消息,服务需要服务连接权限。 默认情况下,每个 IoT 中心都使用名为“服务”的共享访问策略创建,该策略会授予此权限。

若要获取 service策略的 IoT 中心连接字符串,请执行以下步骤:

  1. Azure 门户中,选择“资源组”。 选择中心所在的资源组,然后从资源列表中选择中心。

  2. 在 IoT 中心的左侧窗格上,选择“共享访问策略”。

  3. 在策略列表中,选择“service”策略。

  4. 复制“主连接字符串”并保存该值。

屏幕截图显示如何在 Azure 门户中从 IoT 中心检索连接字符串。

有关 IoT 中心共享访问策略和权限的详细信息,请参阅访问控制和权限

发送云到设备的消息

在本部分中,会创建 Java 控制台应用,用于向模拟设备应用发送“云到设备”消息。 需要设备的设备 ID 和 IoT 中心连接字符串。

  1. 在命令提示符处使用以下命令,创建名为 send-c2d-messages 的 Maven 项目。 请注意,此命令是一条很长的命令:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=send-c2d-messages -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. 在命令提示符下,导航到新的 send-c2d-messages 文件夹。

  3. 使用文本编辑器,打开 send-c2d-messages 文件夹中的 pom.xml 文件,并在 dependencies 节点中添加以下依赖项。 这样即可使用应用程序中的 iothub-java-service-client 包来与 IoT 中心服务通信:

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-service-client</artifactId>
      <version>1.7.23</version>
    </dependency>
    

    注意

    可以使用 Maven 搜索检查是否有最新版本的 iot-service-client

  4. 保存并关闭 pom.xml 文件。

  5. 使用文本编辑器打开 send-c2d-messages\src\main\java\com\mycompany\app\App.java 文件。

  6. 在该文件中添加以下 import 语句:

    import com.microsoft.azure.sdk.iot.service.*;
    import java.io.IOException;
    import java.net.URISyntaxException;
    
  7. 将以下类级变量添加到 App 类,并将 {yourhubconnectionstring} 和 {yourdeviceid} 替换为前面记下的值 :

    private static final String connectionString = "{yourhubconnectionstring}";
    private static final String deviceId = "{yourdeviceid}";
    private static final IotHubServiceClientProtocol protocol =    
        IotHubServiceClientProtocol.AMQPS;
    
  8. main方法替换为以下代码。 此代码用于连接到 IoT 中心,将消息发送到设备,然后等待设备已接收并处理消息的通知:

    public static void main(String[] args) throws IOException,
        URISyntaxException, Exception {
      ServiceClient serviceClient = ServiceClient.createFromConnectionString(
        connectionString, protocol);
    
      if (serviceClient != null) {
        serviceClient.open();
        FeedbackReceiver feedbackReceiver = serviceClient
          .getFeedbackReceiver();
        if (feedbackReceiver != null) feedbackReceiver.open();
    
        Message messageToSend = new Message("Cloud to device message.");
        messageToSend.setDeliveryAcknowledgement(DeliveryAcknowledgement.Full);
    
        serviceClient.send(deviceId, messageToSend);
        System.out.println("Message sent to device");
    
        FeedbackBatch feedbackBatch = feedbackReceiver.receive(10000);
        if (feedbackBatch != null) {
          System.out.println("Message feedback received, feedback time: "
            + feedbackBatch.getEnqueuedTimeUtc().toString());
        }
    
        if (feedbackReceiver != null) feedbackReceiver.close();
        serviceClient.close();
      }
    }
    

    注意

    为简单起见,本文不实现重试策略。 在生产代码中,应该按暂时性故障处理一文中所述实施重试策略(例如指数退避)。

  9. 若要使用 Maven 生成 send-c2d-messages 应用,请在 simulated-device 文件夹中的命令提示符下执行以下命令:

    mvn clean package -DskipTests
    

运行应用程序

现在已准备就绪,可以运行应用程序了。

  1. azure-iot-sdk-java\iothub\device\iot-device-samples\handle-messages 文件夹中的命令提示符处,运行以下命令,将 {Your device connection string} 占位符值替换为从 IoT 中心内注册的设备复制的设备连接字符串。 此步骤启动示例设备应用,将遥测数据发送到 IoT 中心,并侦听从中心发送的云到设备消息:

    java -jar ./target/handle-messages-1.0.0-with-deps.jar "{Your device connection string}"
    

    在控制台窗口中运行的示例设备应用的屏幕截图。

  2. send-c2d-messages 文件夹的命令提示符处,运行以下命令以发送云到设备的消息并等待反馈确认:

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    在控制台窗口中运行的示例服务应用的屏幕截图。

后续步骤

本文已介绍了如何发送和接收云到设备消息。