IoT 设备流式传输未连接
IoT Device Streaming is not connecting
我正在探索 Azure IoT Hub Device Streams 功能。
我有一个 C# 客户端连接到 IoT 中心(位于美国中部)并且处于活动状态。
客户端正在使用以下算法等待传入连接(使用 SDK 版本 1.29.0-preview-004):
var buffer = new byte[1024];
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
DeviceStreamRequest streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationTokenSource.Token);
if (streamRequest is null)
return;
在服务器端,我有一个在特定端点上调用的 Azure 应用服务。它检索 IoT 中心的连接字符串
ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Constants.IoTHub.ConnectionString, TransportType.Amqp);
DeviceStreamRequest deviceStreamRequest = new DeviceStreamRequest("portal");
DeviceStreamResponse result = await serviceClient.CreateStreamAsync(serialNumber, deviceStreamRequest);
我无法建立连接。 CreateStreamAsync
调用在 1 分钟后超时,客户端似乎永远无法退出 WaitForDeviceStreamRequestAsync
调用。
我已按照 troubleshooting guide 了解发生了什么,但我什么也没得到:
问题
为什么我遗漏了会阻止 IoT 设备流式传输连接的内容?
请注意,Azure IoT 中心设备流功能仍处于 public 预览阶段(超过一年)。
您在设备端使用 SDK 1.29.0-preview-004,在服务端使用 1.27.0-preview-004,示例 DeviceStreamingSample 来自 azure-iot-samples-csharp-master 包。
设备流功能用于服务和设备之间的握手过程,与调用设备方法的通信概念相同。可以使用 REST POST 请求轻松测试此握手阶段。
出于演示目的,我将使用我的 IoT Hub Tester,其中已实现设备流功能,请参阅附录 A2 部分中的更多详细信息。
第 1 步。运行 设备的 DeviceClientStreamingSample 程序。你应该使用Transport.Amqp。请注意,其他人在我的测试中失败了。
步骤 2. 使用 REST 客户端工具生成 POST 请求。以下url是我的测试:
https://xxxxxxxxxxx.azure-devices.net/twins/device1/streams/teststream?api-version=2018-08-30-preview
headers:
accept: application/json
iothub-streaming-response-timeout-in-seconds: 15
iothub-streaming-connect-timeout-in-seconds: 5
Authorization: sas-token
有效负载:
任何或空
以下屏幕片段展示了 POST 已发送到设备 1:
并且以下代码片段显示了在 WaitForDeviceStreamRequestAsync 方法之后的断点处停止程序:
设备和服务(在本例中是我的测试仪)之间的完整握手和流式传输显示在以下屏幕片段中:
正如我提到的,Azure IoT 中心测试器已经实现了设备流功能,以下屏幕片段显示了流缓冲区:
注意,运行TransportType.Mqtt的模拟设备不工作,症状和你一样,超时。看起来(基于 REST POST 响应),为 $iothub/streams/POST/#[=23 等主题订阅设备时存在错误=]
但是,当您的设备使用直接 MQTT 协议连接到 IoT 中心时,一切正常,请参阅我的测试仪的屏幕片段,其中 device1 连接到物联网中心:
屏幕上出现 Azure IoT 中心测试器后,您可以使用它来测试用于流式传输的服务 SDK,例如 SDK 示例中的以下行:
DeviceStreamResponse result = await _serviceClient.CreateStreamAsync(_deviceId, deviceStreamRequest).ConfigureAwait(false);
总之,根据我的上述测试,当模拟设备配置为 TransportType.Amqp 协议时,您应该可以成功使用 SDK 进行流式传输。
更新:
在使用 REST 客户端工具的情况下,您可以在 headers:
中看到设备握手的响应
此响应由以下行生成:
await _deviceClient.AcceptDeviceStreamRequestAsync(streamRequest, cancellationTokenSource.Token).ConfigureAwait(false);
基于响应 headers 例如
iothub-streaming-is-accepted
iothub-streaming-url
iothub-streaming-auth-token
可以通过 IoT Hub 在设备和服务之间建立 webSocket 流式通信。
注意,此点之后,使用REST客户端工具模拟设备会失败。
问题出在我使用的 DeviceClient
实例中,它是根据来自配置服务的信息构建的:
ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(Constants.IoTProvisioningService.GlobalDeviceEndpoint, Constants.IoTProvisioningService.IdScope, security, new ProvisioningTransportHandlerHttp());
var result = await provClient.RegisterAsync();
if (result.Status != ProvisioningRegistrationStatusType.Assigned)
return;
var auth = new DeviceAuthenticationWithTpm(result.DeviceId, security);
--> DeviceClient deviceClient = DeviceClient.Create(result.AssignedHub, auth, TransportType.Amqp);
然后我正在使用 DeviceClient
实例来等待请求:
var buffer = new byte[1024];
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
--> DeviceStreamRequest streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationTokenSource.Token);
但是没有用。
我意识到 in the samples (DeviceClientStreamingSample) 连接字符串必须包含我没有的设备 ID:
// String containing Hostname, Device Id & Device Key in one of the following formats:
// "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
// "HostName=<iothub_host_name>;CredentialType=SharedAccessSignature;DeviceId=<device_id>;SharedAccessSignature=SharedAccessSignature sr=<iot_host>/devices/<device_id>&sig=<token>&se=<expiry_time>";
// For this sample either
// - pass this value as a command-prompt argument
// - set the IOTHUB_DEVICE_CONN_STRING environment variable
// - create a launchSettings.json (see launchSettings.json.template) containing the variable
private static string s_deviceConnectionString = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONN_STRING");
所以我停止重复使用从配置服务获得的 DeviceClient
实例并构建了一个新实例(代码尚未准备好生产 - 这是一个原型):
var buffer = new byte[1024];
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var deviceClient = DeviceClient.CreateFromConnectionString(Constants.IoTHub.ConnectionString + $";DeviceId={Constants.Unit.SerialNumber}", TransportType.Amqp);
DeviceStreamRequest streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationTokenSource.Token).ConfigureAwait(false);
if (streamRequest is null)
return;
await deviceClient.AcceptDeviceStreamRequestAsync(streamRequest, cancellationTokenSource.Token);
我正在探索 Azure IoT Hub Device Streams 功能。
我有一个 C# 客户端连接到 IoT 中心(位于美国中部)并且处于活动状态。
客户端正在使用以下算法等待传入连接(使用 SDK 版本 1.29.0-preview-004):
var buffer = new byte[1024];
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
DeviceStreamRequest streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationTokenSource.Token);
if (streamRequest is null)
return;
在服务器端,我有一个在特定端点上调用的 Azure 应用服务。它检索 IoT 中心的连接字符串
ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Constants.IoTHub.ConnectionString, TransportType.Amqp);
DeviceStreamRequest deviceStreamRequest = new DeviceStreamRequest("portal");
DeviceStreamResponse result = await serviceClient.CreateStreamAsync(serialNumber, deviceStreamRequest);
我无法建立连接。 CreateStreamAsync
调用在 1 分钟后超时,客户端似乎永远无法退出 WaitForDeviceStreamRequestAsync
调用。
我已按照 troubleshooting guide 了解发生了什么,但我什么也没得到:
问题
为什么我遗漏了会阻止 IoT 设备流式传输连接的内容?
请注意,Azure IoT 中心设备流功能仍处于 public 预览阶段(超过一年)。 您在设备端使用 SDK 1.29.0-preview-004,在服务端使用 1.27.0-preview-004,示例 DeviceStreamingSample 来自 azure-iot-samples-csharp-master 包。
设备流功能用于服务和设备之间的握手过程,与调用设备方法的通信概念相同。可以使用 REST POST 请求轻松测试此握手阶段。
出于演示目的,我将使用我的 IoT Hub Tester,其中已实现设备流功能,请参阅附录 A2 部分中的更多详细信息。
第 1 步。运行 设备的 DeviceClientStreamingSample 程序。你应该使用Transport.Amqp。请注意,其他人在我的测试中失败了。
步骤 2. 使用 REST 客户端工具生成 POST 请求。以下url是我的测试:
https://xxxxxxxxxxx.azure-devices.net/twins/device1/streams/teststream?api-version=2018-08-30-preview
headers:
accept: application/json
iothub-streaming-response-timeout-in-seconds: 15
iothub-streaming-connect-timeout-in-seconds: 5
Authorization: sas-token
有效负载: 任何或空
以下屏幕片段展示了 POST 已发送到设备 1:
并且以下代码片段显示了在 WaitForDeviceStreamRequestAsync 方法之后的断点处停止程序:
设备和服务(在本例中是我的测试仪)之间的完整握手和流式传输显示在以下屏幕片段中:
正如我提到的,Azure IoT 中心测试器已经实现了设备流功能,以下屏幕片段显示了流缓冲区:
注意,运行TransportType.Mqtt的模拟设备不工作,症状和你一样,超时。看起来(基于 REST POST 响应),为 $iothub/streams/POST/#[=23 等主题订阅设备时存在错误=]
但是,当您的设备使用直接 MQTT 协议连接到 IoT 中心时,一切正常,请参阅我的测试仪的屏幕片段,其中 device1 连接到物联网中心:
屏幕上出现 Azure IoT 中心测试器后,您可以使用它来测试用于流式传输的服务 SDK,例如 SDK 示例中的以下行:
DeviceStreamResponse result = await _serviceClient.CreateStreamAsync(_deviceId, deviceStreamRequest).ConfigureAwait(false);
总之,根据我的上述测试,当模拟设备配置为 TransportType.Amqp 协议时,您应该可以成功使用 SDK 进行流式传输。
更新:
在使用 REST 客户端工具的情况下,您可以在 headers:
中看到设备握手的响应此响应由以下行生成:
await _deviceClient.AcceptDeviceStreamRequestAsync(streamRequest, cancellationTokenSource.Token).ConfigureAwait(false);
基于响应 headers 例如
iothub-streaming-is-accepted
iothub-streaming-url
iothub-streaming-auth-token
可以通过 IoT Hub 在设备和服务之间建立 webSocket 流式通信。 注意,此点之后,使用REST客户端工具模拟设备会失败。
问题出在我使用的 DeviceClient
实例中,它是根据来自配置服务的信息构建的:
ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(Constants.IoTProvisioningService.GlobalDeviceEndpoint, Constants.IoTProvisioningService.IdScope, security, new ProvisioningTransportHandlerHttp());
var result = await provClient.RegisterAsync();
if (result.Status != ProvisioningRegistrationStatusType.Assigned)
return;
var auth = new DeviceAuthenticationWithTpm(result.DeviceId, security);
--> DeviceClient deviceClient = DeviceClient.Create(result.AssignedHub, auth, TransportType.Amqp);
然后我正在使用 DeviceClient
实例来等待请求:
var buffer = new byte[1024];
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
--> DeviceStreamRequest streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationTokenSource.Token);
但是没有用。
我意识到 in the samples (DeviceClientStreamingSample) 连接字符串必须包含我没有的设备 ID:
// String containing Hostname, Device Id & Device Key in one of the following formats:
// "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
// "HostName=<iothub_host_name>;CredentialType=SharedAccessSignature;DeviceId=<device_id>;SharedAccessSignature=SharedAccessSignature sr=<iot_host>/devices/<device_id>&sig=<token>&se=<expiry_time>";
// For this sample either
// - pass this value as a command-prompt argument
// - set the IOTHUB_DEVICE_CONN_STRING environment variable
// - create a launchSettings.json (see launchSettings.json.template) containing the variable
private static string s_deviceConnectionString = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONN_STRING");
所以我停止重复使用从配置服务获得的 DeviceClient
实例并构建了一个新实例(代码尚未准备好生产 - 这是一个原型):
var buffer = new byte[1024];
using var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var deviceClient = DeviceClient.CreateFromConnectionString(Constants.IoTHub.ConnectionString + $";DeviceId={Constants.Unit.SerialNumber}", TransportType.Amqp);
DeviceStreamRequest streamRequest = await deviceClient.WaitForDeviceStreamRequestAsync(cancellationTokenSource.Token).ConfigureAwait(false);
if (streamRequest is null)
return;
await deviceClient.AcceptDeviceStreamRequestAsync(streamRequest, cancellationTokenSource.Token);