我正在探索 Azure IoT Hub设备流 的功能。
我有一个C#客户端连接到IoT Hub(位于美国中部)并处于活动状态。
客户端使用以下算法来等待传入的连接(使用 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 Hub的连接字符串。
ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(Constants.IoTHub.ConnectionString, TransportType.Amqp);
DeviceStreamRequest deviceStreamRequest = new DeviceStreamRequest("portal");
DeviceStreamResponse result = await serviceClient.CreateStreamAsync(serialNumber, deviceStreamRequest);
我无法建立连接。该 CreateStreamAsync
呼叫在1分钟后超时,而客户方似乎永远无法摆脱。WaitForDeviceStreamRequestAsync
呼叫。
我已经按照 故障排除指南 找出什么是怎么回事,但我没有得到任何。
问题:
为什么我缺少了会阻止IoT设备流连接的功能?
请注意,Azure IoT Hub Device Streams 功能仍处于公开预览版(一年多)。您正在使用的SDK 1.29.0-preview-004 在设备侧和 1.27.0-预览-004 在服务方面和样品 设备流样本 来自 azure-iot-samples-csharp-master......。 包。
设备流功能使用服务和设备之间的握手过程,与调用设备方法的通信概念相同。这个握手阶段可以通过一个REST POST请求进行简单的测试。
为了演示的目的,我将使用我的 物联网中枢测试仪在已实现设备流功能的地方,更多细节请参见附录A2部分。
步骤1. 为您的设备运行DeviceClientStreamingSample程序。你应该使用 Transport.Amqp. 注意,其他的人在我的测试中失败了。
第2步:使用REST客户端工具生成POST请求。使用REST客户端工具生成一个POST请求。以下是我测试的url。
https://xxxxxxxxxxx.azure-devices.net/twins/device1/streams/teststream?api-version=2018-08-30-preview
headers: payload: any or empty:
accept: application/json
iothub-streaming-response-timeout-in-seconds: 15
iothub-streaming-connect-timeout-in-seconds: 5
Authorization: sas-token
payload: any or empty
下面的屏幕片段演示了当POST已经被发送到设备1。
下面的片段显示了在断点处停止一个程序后 WaitForDeviceStreamRequestAsync(等待设备流请求)。 方法。
以下屏幕片段显示了设备和服务(在本例中是我的测试器)之间的完整握手和流媒体。
正如我提到的,Azure IoT Hub Tester已经实现了设备流功能,下面的屏幕片段显示了一个流缓冲区。
注意,运行模拟设备为 运输类型.Mqtt 不工作,症状和你一样,超时。看起来(根据REST POST响应),订阅主题的设备有一个bug,例如 $iothubstreamsPOST#
然而,当你的设备使用直接的MQTT协议到IoT Hub时,一切都很好,请看我的测试仪的屏幕片段,其中的 设备1 是连接到IoT Hub的。
一旦你有Azure IoT Hub Tester在屏幕上, 你可以用它来测试一个服务SDK的流,如以下行 从SDK样品。
DeviceStreamResponse result = await _serviceClient.CreateStreamAsync(_deviceId, deviceStreamRequest).ConfigureAwait(false);
总之,根据我上面的测试,当模拟设备配置为以下情况时,你应该可以用SDKs成功地进行流式传输 运输类型.Amqp 协议。
更新。
在使用REST客户端工具的情况下,你可以在头文件中看到设备握手的响应。
这个响应是由以下一行生成的。
await _deviceClient.AcceptDeviceStreamRequestAsync(streamRequest, cancellationTokenSource.Token).ConfigureAwait(false);
基于响应头信息,如
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);
然而,它没有工作。
我意识到 在样本中 (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);