此库适用于任何需要与其他应用程序通信的通用 Windows 平台 (UWP) 应用程序。我在 Raspberry Pi 上运行的个人 Windows IoT 应用程序中广泛使用它。
只需两行即可将 DiscoveryClient 添加到任何应用程序:
var discoveryClient = new DiscoveryClient("1234", "4567");
discoveryClient.Initialize("My Unique Name", serializableStateObject);
第一行将创建一个客户端实例,其中包含要操作的所需 TCP 和 UDP 端口。第二行设置该设备的唯一名称和一个指向保存设备所有状态信息的对象的指针。建议您使用 JObject。启动后,设备将发送一个 IDENTIFY 数据包和一个 DISCOVER 数据包来查找网络上的所有其他设备。
客户端初始化后,您可以使用 LINQ 按设备名称访问设备:
var iotDevice = discoveryClient.Devices.FirstOrDefault(device => device.Name == "iotDeviceName");
一旦您拥有一个对象,您就可以访问名称、IpAdress 和 DeviceInfo - 一个包含设备提供的任何信息的对象。
string iotDeviceIpAddress = iotDevice.IpAddress;
string iotDeviceName = iotDevice.Name;
JObject iotDeviceInfo = iotDevice.DeviceInfo;
Debug.WriteLine($"{iotDevice.Name} at {iotDevice.IpAddress} has a state of {iotDevice.DeviceInfo.GetValue<string>("state")}");
由于客户端在启动时进行识别并尝试发现其他设备,因此一切都应该正常工作:)但是因为我们生活在现实世界中,您可能需要定期发送发现请求以确保您了解所有其他设备。您可以使用 Discover() 函数来做到这一点。
var discoveryTimer = new Timer((state) =>
{
discoveryClient.Discover();
}, null, 0, 30000);
调用 Discover() 会广播一条包含已知设备列表的 UDP 消息。每个设备都会查看该列表,如果它们不存在或者它们的 IP 地址已更改,则会做出响应。这也意味着设备名称必须是唯一的。
有时您会想知道何时添加设备或何时更新设备状态。客户端使用 System.Reactive observables,您可以订阅:
当设备添加时
using System.Reactive.Linq;
using System.Threading;
var whenDeviceAdded = discoveryClient
.WhenDeviceAdded
.ObserveOn(SynchronizationContext.Current)
.Subscribe(device =>
{
Debug.WriteLine("A device was added");
});
设备更新时
using System.Reactive.Linq;
using System.Threading;
var whenDeviceUpdated = discoveryClient
.WhenDeviceUpdated
.ObserveOn(SynchronizationContext.Current)
.Subscribe(device =>
{
Debug.WriteLine("A device was updated");
});
ObserveOn(SynchronizationContext.Current) 用于确保代码在 UI 线程上运行。完成后不要忘记处理订阅;)
一旦发现设备,就可以直接向该设备发送消息。这是利用 TCP 来完成的,以确保消息的传递。每个设备都运行一个轻量级 REST API,用于侦听传入消息。消息可以像字符一样简单,但发送序列化对象更有用。
发送直接消息
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var jMessage = new JObject();
jMessage.Add("powerLevel", 100);
var success = await discoveryClient.SendDirectMessage("myDevice", jMessage.ToString());
当直接消息
using System.Reactive.Linq;
using System.Threading;
var whenDirectMessage = discoveryClient
.WhenDirectMessage
.ObserveOn(SynchronizationContext.Current)
.Subscribe(message => {
var jMessage = JObject.Parse(message);
var powerLevel = message.GetValue<int>("powerLevel");
});