问题
Currently I'm sending Device Messages to an IoTHub on an Azure instance and then all of the messages are sent to an EventHub for Processing.
My objective is to use an Azure Protocol Cloud Gateway to act as an intermediary to receive batched messages and then unwrap them before sending them off for processing. By having the messages batched it will allow me to reduce the amount of data being transmitted, cutting down on data usage costs. Once the data is in the cloud it can be un-compressed and then processed normally.
After some research and playing with the Gateway on my local machine and using some of the Unit tests built into the Solution, I've seen how the messages are sent to the Gateway/IoTHub.
ServiceClient serviceClient = ServiceClient.CreateFromConnectionString(iotHubConnectionString);
Stopwatch sw = Stopwatch.StartNew();
await this.CleanupDeviceQueueAsync(hubConnectionStringBuilder.HostName, device);
var clientScenarios = new ClientScenarios(hubConnectionStringBuilder.HostName, this.deviceId, this.deviceSas);
var group = new MultithreadEventLoopGroup();
string targetHost = this.tlsCertificate.GetNameInfo(X509NameType.DnsName, false);
var readHandler1 = new ReadListeningHandler(CommunicationTimeout);
Bootstrap bootstrap = new Bootstrap()
.Group(group)
.Channel<TcpSocketChannel>()
.Option(ChannelOption.TcpNodelay, true)
.Handler(this.ComposeClientChannelInitializer(targetHost, readHandler1));
IChannel clientChannel = await bootstrap.ConnectAsync(this.ServerAddress, protocolGatewayPort);
this.ScheduleCleanup(() => clientChannel.CloseAsync());
Task testWorkTask = Task.Run(async () =>
{ //Where the messaging actually starts and sends
Tuple<EventData, string>[] ehMessages = await CollectEventHubMessagesAsync(receivers, 2); //Async task for recieving messages back from the IoTHub
Tuple<EventData, string> qos0Event = Assert.Single(ehMessages.Where(x => TelemetryQoS0Content.Equals(x.Item2, StringComparison.Ordinal)));
Tuple<EventData, string> qos1Event = Assert.Single(ehMessages.Where(x => TelemetryQoS1Content.Equals(x.Item2, StringComparison.Ordinal)));
string qosPropertyName = ConfigurationManager.AppSettings["QoSPropertyName"];
var qos0Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS0Content));
qos0Notification.Properties[qosPropertyName] = "0";
qos0Notification.Properties["subTopic"] = "tips";
await serviceClient.SendAsync(this.deviceId, qos0Notification);
var qos1Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS1Content));
qos1Notification.Properties["subTopic"] = "firmware-update";
await serviceClient.SendAsync(this.deviceId, qos1Notification);
var qos2Notification = new Message(Encoding.UTF8.GetBytes(NotificationQoS2Content));
qos2Notification.Properties[qosPropertyName] = "2";
qos2Notification.Properties["subTopic"] = "critical-alert";
await serviceClient.SendAsync(this.deviceId, qos2Notification);
var qos2Notification2 = new Message(Encoding.UTF8.GetBytes(NotificationQoS2Content2));
qos2Notification2.Properties[qosPropertyName] = "2";
await serviceClient.SendAsync(this.deviceId, qos2Notification2);
});
So the "ServiceClient" sends 4 messages in this unit test: qos0Notification, qos1Notification, qos2Notification, qos2Notification2, and uses a SendAsync method to send the information.
The SendAsync method is part of the base code for the application and is not available to view.The method also takes a DeviceId and a Message Object. Message has 3 overloads for the Object: Base, a Byte Stream, or a Byte Array.
Once the Gateway is initialized it receives it's messages using this method:
public override void ChannelRead(IChannelHandlerContext context, object message)
{
var packet = message as Packet;
if (packet == null)
{
CommonEventSource.Log.Warning($"Unexpected message (only `{typeof(Packet).FullName}` descendants are supported): {message}", this.ChannelId);
return;
}
this.lastClientActivityTime = DateTime.UtcNow; // notice last client activity - used in handling disconnects on keep-alive timeout
if (this.IsInState(StateFlags.Connected) || packet.PacketType == PacketType.CONNECT)
{
this.ProcessMessage(context, packet);
}
else
{
if (this.IsInState(StateFlags.ProcessingConnect))
{
Queue<Packet> queue = this.connectPendingQueue ?? (this.connectPendingQueue = new Queue<Packet>(4));
queue.Enqueue(packet);
}
else
{
// we did not start processing CONNECT yet which means we haven't received it yet but the packet of different type has arrived.
ShutdownOnError(context, string.Empty, new InvalidOperationException($"First packet in the session must be CONNECT. Observed: {packet}, channel id: {this.ChannelId}, identity: {this.identity}"));
}
}
}
I feel like this would be the best place to unwrap any batched messages. Once we have a list of messages we would send them off to ProcessMessage to determine what kind of message it is and how to handle it.
It seems as though there isn't a lot of information available for this since it's very new.
回答1:
After some research and playing with the Gateway on my local machine and using some of the Unit tests built into the Solution, I've seen how the messages are sent to the Gateway/IoTHub.
Here, ServiceClient
sends messages to devices not to IoTHub. This kind of messages are Cloud-To-Device messages. You can use DeviceClient
to send Device-To-Cloud messages.
My objective is to use an Azure Protocol Cloud Gateway to act as an intermediary to receive batched messages and then unwrap them before sending them off for processing. By having the messages batched it will allow me to reduce the amount of data being transmitted, cutting down on data usage costs.
By You can inject custom process to reduce the data that will be passed to IoTHub. Well, you can add custom channel handlers.
Protocol gateway uses pipeline-based message processing using the following handlers: TLS encryption/decryption, MQTT codec (encoder and decoder), and MqttIotHubAdapter. One way for customizing the gateway behavior is by injecting additional handlers in this pipeline. By adding a custom handler between the MQTT codec and the MqttIotHubAdapter you can inspect, modify, discard, delay, or split the passing messages.
More information and sample code you can reference "Microsoft Azure IoT Protocol Gateway Developer Guide".
来源:https://stackoverflow.com/questions/42404223/sending-receiving-batch-messages-to-azure-protocol-gateway