簡體   English   中英

Azure IoT 中心中的 TCP 支持

[英]TCP support in Azure IoT Hub

Azure IoT 中心支持 AMQP、MQTT、HTTP 協議。 為了自定義這些協議,我們有 Azure IoT 協議網關。 我可以找到關於 MQTT 協議定制的好樣本。 我需要一些使用 Azure IoT 協議網關進行基於 TCP 的協議自定義的示例代碼。

編輯(為了得到答案): OP 所問的是使用 Azure 協議網關來支持基於 TCP 的專有協議的示例 目前物聯網中心僅支持 AMQP、MQTT 和 HTTP。 雖然這些協議實際上依賴於 TCP,但如果沒有額外的 AMQP、MQTT 或 HTTP 層,集線器不支持直接 TCP 連接。 正如 這里所解釋的,我們需要一個基於自定義 TCP 協議的基本示例。

想象一個基本設備,它只能在給定的 IP 地址/端口上通過 TCP 發送一些專有負載:我們需要一個網關定制示例,允許該設備向集線器發送數據。

協議網關的當前代碼設計不佳,因為它嚴重依賴於 MQTT。

也增加了一些賞金。

由於所有 MQTT 代碼,默認協議網關示例確實有些令人困惑。 協議網關的工作原理是為您連接到網關的每個自定義協議設備“模擬”一個 IoTHub 連接。

要完成從 TCP 設備到 IoTHub 設備的轉換,您首先需要代表設備連接到 IoTHub。 這是網關部分。 以下是此 IoTHubConnection 的核心要素。

namespace GatewayTest
{
    using System;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using DotNetty.Buffers;
    using Microsoft.Azure.Devices.ProtocolGateway.Identity;
    using Microsoft.Azure.Devices.ProtocolGateway.IotHubClient;
    using Microsoft.Azure.Devices.ProtocolGateway.Messaging;

    public class IoTHubConnection : IMessagingChannel<IMessage>
    {
        private readonly string iotHubHostName;
        private readonly Func<IDeviceIdentity, Task<IMessagingServiceClient>> deviceClientFactory;
        private readonly Func<string, Task> onMessage;
        private IMessagingServiceClient deviceClient;
        private IDeviceIdentity deviceIdentity;

        public IoTHubConnection(
            string iotHubHostName,
            Func<IDeviceIdentity, Task<IMessagingServiceClient>> deviceClientFactory,
            Func<string, Task> onMessage)
        {
            this.iotHubHostName = iotHubHostName;
            this.deviceClientFactory = deviceClientFactory;
            this.onMessage = onMessage;
        }

        public event EventHandler CapabilitiesChanged;

        public async Task OpenAsync(string deviceId, string deviceKey)
        {
            this.deviceIdentity = this.GetDeviceIdentity(deviceId, deviceKey);
            if (this.deviceIdentity != UnauthenticatedDeviceIdentity.Instance)
            {
                this.deviceClient = await this.deviceClientFactory(this.deviceIdentity);
                this.deviceClient.BindMessagingChannel(this);
            }
        }

        public async Task CloseAsync()
        {
            await this.deviceClient.DisposeAsync(null);
            this.deviceClient = null;
        }

        public void Handle(IMessage message)
        {
            var messageBody = message.Payload.ToString(Encoding.UTF8);

            this.onMessage(messageBody);

            this.deviceClient.CompleteAsync(message.Id);
        }

        public Task SendMessage(string message)
        {
            var buffer = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(message));
            var deviceMessage = this.deviceClient.CreateMessage($"devices/{this.deviceIdentity.Id}/messages/events", buffer);
            return this.deviceClient.SendAsync(deviceMessage);
        }

        protected virtual void OnCapabilitiesChanged(EventArgs e)
        {
            this.CapabilitiesChanged?.Invoke(this, e);
        }

        private IDeviceIdentity GetDeviceIdentity(string userName, string deviceKey)
        {
            IotHubDeviceIdentity ideviceIdentity;
            if (!IotHubDeviceIdentity.TryParse($"{this.iotHubHostName}/{userName}", out ideviceIdentity))
            {
                return UnauthenticatedDeviceIdentity.Instance;
            }

            ideviceIdentity.WithDeviceKey(deviceKey);
            return ideviceIdentity;
        }
    }
}

deviceClientFactory 回調方法應按如下所示實現,並在 Github 的 ProtocolGateway 存儲庫中的這一行中實現。

deviceClientFactory = IotHubClient.PreparePoolFactory(
    "IotHubConnectionString",
    400,
    TimeSpan.FromMinutes(3),
    iotHubClientSettings,
    PooledByteBufferAllocator.Default,
    new ConfigurableMessageAddressConverter("TopicNameConversion"));

當 Tcp 設備連接到協議時,您應該創建此 IoTHubConnection 的實例並將消息從設備發送到 IoTHubConnection,反之亦然。 下面的代碼顯示了如何完成此操作的非常簡單的版本。

private const int BufferSize = 1024;
private byte[] buffer = new byte[BufferSize];
private IoTHubConnection ioTHubConnection;
private NetworkStream stream;

private async Task Start()
{
    listener = new TcpListener(IPAddress.Any, port);
    listener.Start();

    var client = await listener.AcceptTcpClientAsync();
    ioTHubConnection = new IoTHubConnection("IoTHubName", deviceClientFactory, OnIoTHubMessage);
    stream = client.GetStream();

    // Read DeviceId and DeviceKey from some sort of StartConnection-message send by the TcpClient.
    await ioTHubConnection.OpenAsync("DeviceId", "DeviceKey");

    stream.BeginRead(buffer, 0, BufferSize, ReadTcpStreamCallback, null);
}

private void ReadTcpStreamCallback(IAsyncResult ar)
{
    var bytesRead = stream.EndRead(ar);

    if (bytesRead > 0)
    {
        var message = System.Text.Encoding.ASCII.GetString(result);

        ioTHubConnection.SendMessage(message);

        // Read again.
        stream.BeginRead(buffer, 0, BufferSize, ReadTcpStreamCallback, null);
    }
}

private async Task OnIoTHubMessage(string message)
{
    // Potentially do some translation on the IoTHub message
    // and send it to the Device

    var byteData = Encoding.UTF8.GetBytes(message);
    stream.BeginWrite(byteData, 0, byteData.Length, SendTcpCallback, null);
}

private void SendTcpCallback(IAsyncResult ar)
{
    stream.EndWrite(ar);
}

我知道這次談話我遲到了。 但是,我有一些有趣的補充,或者可能是某些人的解決方案。

Azure IoT 網關現在被稱為 Azure IoT Edge,這在下面的 Azure github repo 中有明確提到

在此處輸入圖片說明

https://github.com/Azure/iot-edge-modbus.git

另一方面,Azure IoT Edge 支持某些協議的 TCP,可在以下鏈接中找到

  1. https://docs.microsoft.com/en-us/azure/iot-edge/deploy-modbus-gateway
  2. https://docs.microsoft.com/en-us/azure/iot-edge/iot-edge-as-gateway

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM