此程式庫適用於任何需要與其他應用程式通訊的通用 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");
});