首页 文章

Azure IoT Hub中的TCP支持

提问于
浏览
13

Azure IoT Hub支持AMQP,MQTT,HTTP协议 . 为了自定义这些协议,我们有Azure IoT协议网关 . 我可以在MQTT协议定制上找到好的样本 . 我需要一些使用Azure IoT协议网关进行基于TCP的协议自定义的示例代码 .

EDIT (in order to get an answer): OP正在询问的是使用Azure协议网关 to support a proprietary TCP-based protocol 的示例 . 目前,IoT中心仅支持AMQP,MQTT和HTTP . 虽然这些协议实际上依赖于TCP,但如果没有额外的AMQP,MQTT或HTTP层,则集线器不支持直接TCP连接 . 正如here所解释的,我们需要一个基于TCP的自定义协议的基本示例 .

想象一下,一个基本设备只能通过TCP在给定的IP地址/端口上发送一些专有的有效载荷:我们需要一个网关定制的例子,允许该设备将数据发送到集线器 .

协议网关的当前代码设计很差,因为它严重依赖于MQTT .

也加上一些赏金 .

1 回答

  • 2

    由于所有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 repo中的this line中实现 .

    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);
    }
    

相关问题