使用 IoT 中心发送云到设备消息 (.NET)

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

本文介绍如何:

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

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

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

注意

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

在本文结束时,会运行两个 .NET 控制台应用。

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

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

注意

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

可以在 IoT 中心的 D2C 和 C2D 消息传送中找到有关“云到设备”消息的详细信息。

先决条件

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

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

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

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

    • 将 SDK 存储库从 GitHub 下载或克隆到开发计算机。
    • 确保在开发计算机上安装 .NET Core 3.0.0 或更高版本。 运行 dotnet --version 来检查版本,如有必要,请下载 .NET
  • 确保已在防火墙中打开端口 8883。 本文中的设备示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)

  • Visual Studio。

获取设备连接字符串

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

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

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

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

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

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

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

在设备应用中接收消息

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

dotnet restore
dotnet run --c "{Your device connection string}"

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

5/22/2023 11:13:18 AM> Press Control+C at any time to quit the sample.
     
5/22/2023 11:13:18 AM> Device waiting for C2D messages from the hub...
5/22/2023 11:13:18 AM> Use the Azure Portal IoT hub blade or Azure IoT Explorer to send a message to this device.
5/22/2023 11:13:18 AM> Trying to receive C2D messages by polling using the ReceiveAsync() method. Press 'n' to move to the next phase.

示例设备应用使用 ReceiveAsyncCompleteAsync 方法轮询消息。 ReceiveC2dMessagesPollingAndCompleteAsync 方法使用 ReceiveAsync 方法,以便在设备收到消息时以异步方式返回收到的消息。 ReceiveAsync 在可指定的超时期限过后返回 null。 在此示例中,使用默认值一分钟。 当设备收到 null 时,它应继续等待新消息。 此要求是示例应用在 ReceiveC2dMessagesPollingAndCompleteAsync 方法中包含以下代码块的原因:

   if (receivedMessage == null)
   {
      continue;
   }

CompleteAsync 方法的调用会通知 IoT 中心,指出已成功处理消息,且可以安全地从设备队列中删除该消息。 无论其使用何种协议,设备都应在处理成功完成后调用此方法。

使用 AMQP 和 HTTPS 协议(而不是 MQTT 协议),设备还可以:

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

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

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

注意

使用 HTTPS 而不使用 MQTT 或 AMQP 作为传输时,ReceiveAsync 方法将立即返回。 使用 HTTPS 的云到设备消息,其支持模式是间歇连接到设备,且不常检查消息(至少每 25 分钟检查一次)。 发出更多 HTTPS 接收会导致 IoT 中心限制请求。 有关 MQTT、AMQP 和 HTTPS 支持之间的差异的详细信息,请参阅云到设备通信指南选择通信协议

获取 IoT 中心连接字符串

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

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

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

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

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

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

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

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

发送云到设备的消息

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

  1. 在 Visual Studio 中,选择“文件”>“新建”>“项目”。 在“创建新项目”中,选择“控制台应用(.NET Framework)”,然后选择“下一步” 。

  2. 将项目命名为 SendCloudToDevice,然后选择“下一步”。

    Visual Studio 中“配置新项目”弹出窗口的屏幕截图。

  3. 接受最新版本的.NET Framework。 选择“创建”来创建项目。

  4. 在“解决方案资源管理器”中,右键单击新项目,然后选择“管理 NuGet 包”。

  5. 在“管理 NuGet 程序包”中,选择“浏览”,然后搜索并选择“Microsoft.Azure.Devices”。 选择“安装” 。

    此步骤会下载、安装 Azure IoT 服务 SDK NuGet 包并添加对它的引用。

  6. 在 Program.cs 文件顶部添加以下 using 语句。

    using Microsoft.Azure.Devices;
    
  7. 将以下字段添加到 Program 类。 将 {iot hub connection string} 占位符值替换为先前在获取 IoT 中心连接字符串中记下的 IoT 中心连接字符串。 将 {device id} 占位符值替换为 IoT 中心中的已注册设备的设备 ID。

    static ServiceClient serviceClient;
    static string connectionString = "{iot hub connection string}";
    static string targetDevice = "{device id}";
    
  8. 将以下方法添加到 Program 类,以便将消息发送到设备。

    private async static Task SendCloudToDeviceMessageAsync()
    {
         var commandMessage = new
          Message(Encoding.ASCII.GetBytes("Cloud to device message."));
         await serviceClient.SendAsync(targetDevice, commandMessage);
    }
    
  9. 最后,将下面的行添加到 Main 方法。

    Console.WriteLine("Send Cloud-to-Device message\n");
    serviceClient = ServiceClient.CreateFromConnectionString(connectionString);
    
    Console.WriteLine("Press any key to send a C2D message.");
    Console.ReadLine();
    SendCloudToDeviceMessageAsync().Wait();
    Console.ReadLine();
    
  10. 按“F5”启动示例服务应用。 选择“SendCloudToDevice”窗口并按“Enter” 。 应会看到示例设备应用收到的消息,如以下输出示例中所示。

    5/22/2023 11:13:18 AM> Press Control+C at any time to quit the sample.
    
    5/22/2023 11:13:18 AM> Device waiting for C2D messages from the hub...
    5/22/2023 11:13:18 AM> Use the Azure Portal IoT hub blade or Azure IoT Explorer to send a message to this device.
    5/22/2023 11:13:18 AM> Trying to receive C2D messages by polling using the ReceiveAsync() method. Press 'n' to move to the next phase.
    5/22/2023 11:15:18 AM> Polling using ReceiveAsync() - received message with Id=
    5/22/2023 11:15:18 AM> Received message: [Cloud to device message.]
            Content type:
    
    5/22/2023 11:15:18 AM> Completed C2D message with Id=.
    

接收送达反馈

可以从 IoT 中心请求每个云到设备消息的送达(或过期)确认。 借助此选项,解决方案后端能够轻松地通知、重试或补偿逻辑。 有关云到设备反馈的详细信息,请参阅 IoT 中心的 D2C 和 C2D 消息传送

在本部分中,修改“SendCloudToDevice”示例服务应用以请求反馈,并接收来自 IoT 中心的反馈。

  1. 在 Visual Studio 中的 SendCloudToDevice 项目内,将以下方法添加到 Program 类。

    private async static void ReceiveFeedbackAsync()
    {
         var feedbackReceiver = serviceClient.GetFeedbackReceiver();
    
         Console.WriteLine("\nReceiving c2d feedback from service");
         while (true)
         {
             var feedbackBatch = await feedbackReceiver.ReceiveAsync();
             if (feedbackBatch == null) continue;
    
             Console.ForegroundColor = ConsoleColor.Yellow;
             Console.WriteLine("Received feedback: {0}",
               string.Join(", ", feedbackBatch.Records.Select(f => f.StatusCode)));
             Console.ResetColor();
    
             await feedbackReceiver.CompleteAsync(feedbackBatch);
         }
     }
    

    请注意,此接收模式与用于从设备应用接收云到设备消息的模式相同。

  2. 在 Main 方法中的 serviceClient = ServiceClient.CreateFromConnectionString(connectionString) 后面添加以下行。

    ReceiveFeedbackAsync();
    
  3. 若要请求针对传递云到设备消息的反馈,必须在 SendCloudToDeviceMessageAsync 方法中指定一个属性。 紧接在 var commandMessage = new Message(...); 行的后面添加以下行。

    commandMessage.Ack = DeliveryAcknowledgement.Full;
    
  4. 确保示例设备应用正在运行,然后按“F5”运行示例服务应用。 选择“SendCloudToDevice”控制台窗口并按“Enter”。 应会看到示例设备应用正在接收的消息,几秒钟后,“SendCloudToDevice”应用程序将收到反馈消息。 以下输出显示示例服务应用收到的反馈消息:

    Send Cloud-to-Device message
    
    
    Receiving c2d feedback from service
    Press any key to send a C2D message.
    
    Received feedback: Success
    

注意

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

后续步骤

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