using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using Shared.Common; using ZigBee.Device; namespace ZigBee.Common { public static class Application { public static bool isInited; /// /// 是否正在搜索网关 /// public static bool IsSearchingGateway = false; /// /// 新发现的网关通知 /// public static Action NewGateWayAction; /// /// 上一次的住宅ID /// private static string oldHomeID = string.Empty; public static void Init() { if (isInited) { return; } isInited = true; new System.Threading.Thread(async () => { var gateWayList = new List { }; var searchCount = 6; var broadBytes = new byte[44];// byteHomeId[0] ,//H broadBytes[0] = 0xfe; broadBytes[1] = 0x29; broadBytes[2] = 0x00; broadBytes[3] = 0x00; broadBytes[4] = 0x00; broadBytes[5] = 0x00; broadBytes[6] = 0x00; broadBytes[43] = 0x02; while (true) { try { if (string.IsNullOrEmpty(Shared.Common.Config.Instance.HomeId)) { //住宅ID为空只有一种可能就是退出了登录,这里的上一次住宅ID要清空 oldHomeID = "?"; System.Threading.Thread.Sleep(1000); continue; } //首次进入网关,和切换住宅会清除网关列表,重新搜索存储 if (Shared.Common.Config.Instance.HomeId != oldHomeID) { //因为那一瞬间,有可能mqtt会加回来,所以先加缓存 var list = new List(); list.AddRange(ZbGateway.GateWayList); //然后清空掉 ZbGateway.GateWayList.Clear(); //最后再断开mqtt连接 for (int i = 0; i < list.Count; i++) { list[i].DisConnectLocalMqttClient("1"); } list.Clear(); oldHomeID = Shared.Common.Config.Instance.HomeId; var tempBytes = System.Text.Encoding.UTF8.GetBytes(Shared.Common.Config.Instance.HomeId); System.Array.Copy(tempBytes, 0, broadBytes, 7, 36 < tempBytes.Length ? 36 : tempBytes.Length); //住宅中已经存在的网关如果局域网不存在,需要在当前住宅中虚拟一个网关ID相同的网关 var gateWayFileList = Global.FileListByHomeId().FindAll(obj => obj.StartsWith("Gateway_")); foreach (var filePath in gateWayFileList) { var paths = filePath.Split('_'); if (paths.Length < 3) continue; var gateWay = ZbGateway.GateWayList.Find(obj => (obj != null) && (obj.GwId == paths[2])); if (gateWay == null) { gateWay = new ZbGateway { IsVirtual = true }; gateWay.GwId = paths[2]; gateWay.HomeId = Shared.Common.Config.Instance.HomeId; ZbGateway.GateWayList.Add(gateWay); } } } var broadcastIpAddress = new Shared.Net.NetWiFi().BroadcastIpAddress; if (Shared.Application.IsWifi) { if (0 < gateWayList.Count) { searchCount = 6; ZbGateway.IsRemote = false; //当网关的连接方式改变时,记录当前的连接方式 Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.WIFI); } else { if (searchCount < 0) { ZbGateway.IsRemote = true; //当网关的连接方式改变时,记录当前的连接方式 Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.Remote); } } } else { ZbGateway.IsRemote = true; //当网关的连接方式改变时,记录当前的连接方式 Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.Remote); for (int i = 0; i < ZbGateway.GateWayList.Count; i++) { ZbGateway.GateWayList[i].DisConnectLocalMqttClient("1"); } } searchCount--; #region 1秒搜索一次网关 //每0.5秒广播发现一次网关,共1s int count = 2; new System.Threading.Thread(() => { gateWayList.Clear(); while (0 < count--) { try { //点对点发送(先发一条已有的点播,回复几率高一点) for (int i = 0; i < gateWayList.Count; i++) { FindGateWaySocket.BeginSend(new System.Net.IPEndPoint(System.Net.IPAddress.Parse(gateWayList[i].GwIP), 7624), broadBytes); } //广播发送 if (broadcastIpAddress.ToString() != "0.0.0.0") { FindGateWaySocket.BeginSend(new System.Net.IPEndPoint(broadcastIpAddress, 7624), broadBytes); } } catch { //关闭Socket,下次发送会自动连接 FindGateWaySocket.Stop(); } System.Threading.Thread.Sleep(500); } }) { IsBackground = true }.Start(); while (0 < count) { try { if (FindGateWaySocket.busSocket == null) { System.Threading.Thread.Sleep(100); continue; } var bytes = new byte[1024]; var len = FindGateWaySocket.busSocket.Receive(bytes, bytes.Length, System.Net.Sockets.SocketFlags.None); if (bytes[43] == 0xA2) { //广播回复网关的基本信息处理 var ipAddress = $"{bytes[3]}.{bytes[4]}.{bytes[5]}.{bytes[6]}"; var homeID = System.Text.Encoding.UTF8.GetString(bytes, 7, 36); homeID = homeID.Replace('\0', ' ').Trim(); var isMainGateWay = bytes[44] == 1; var time = (bytes[48] & 0xff) << 24 | (bytes[47] & 0xff) << 16 | (bytes[46] & 0xff) << 8 | (bytes[45] & 0xff); var gwNameLength = bytes[49]; var gwName = System.Text.Encoding.UTF8.GetString(bytes, 50, gwNameLength); var gwIdLength = bytes[49 + gwNameLength + 1]; var id = Encoding.UTF8.GetString(bytes, 49 + gwNameLength + 2, gwIdLength); var pubKeyLengthByte0 = bytes[49 + gwNameLength + 1 + gwIdLength + 1]; var pubKeyLengthByte1 = bytes[49 + gwNameLength + 1 + gwIdLength + 2]; int pubKeyLength = ((pubKeyLengthByte1 & 0xff) << 8 | (pubKeyLengthByte0 & 0xff)); var pubKey = Encoding.UTF8.GetString(bytes, 49 + gwNameLength + 1 + gwIdLength + 2 + 1, pubKeyLength); var zbGateWay = new ZbGateway { GwIP = ipAddress, GwName = gwName, HomeId = homeID, IsMainGateWay = isMainGateWay, GwId = id, GatewayOnlineFlage = true, PubKey = pubKey }; //通讯到网关列表 if (gateWayList.Find(obj => obj.GwId == zbGateWay.GwId) == null) { //网关匹配当前住宅中到网关 if (Shared.Common.Config.Instance.HomeId == homeID) { gateWayList.Add(zbGateWay); } //UI界面正在搜索,不必配当前住宅到到网关此时也通讯 else if (IsSearchingGateway) { gateWayList.Add(zbGateWay); } //网关中到住宅ID为空此时也通讯 2020.01.14变更:没这个必要,上面那个变量就能处理 //else if (homeID == string.Empty) //{ // gateWayList.Add(zbGateWay); //} } //网关列表存储处理 var gateWay = ZbGateway.GateWayList.Find(obj => obj.GwId == zbGateWay.GwId); if (gateWay == null) { ZbGateway.GateWayList.Add(zbGateWay); await zbGateWay.StartLocalMqtt(ipAddress); NewGateWayAction?.Invoke(zbGateWay); } else { gateWay.IsVirtual = false; //将该网关标识为【可搜索到,即:在线】 gateWay.GatewayOnlineFlage = true; if (gateWay.GwIP != ipAddress) { await gateWay.DisConnectLocalMqttClient("2"); ZbGateway.GateWayList.Remove(gateWay); gateWay = zbGateWay; ZbGateway.GateWayList.Add(gateWay); await zbGateWay.StartLocalMqtt(ipAddress); } else { gateWay.PubKey = pubKey; gateWay.GwName = gwName; gateWay.HomeId = homeID; await gateWay.StartLocalMqtt(ipAddress); } //主网关设置 if (isMainGateWay && oldHomeID == gateWay.HomeId) { for (int i = 0; i < ZbGateway.GateWayList.Count; i++) { var gw = ZbGateway.GateWayList[i]; //网关ID不是当前的网关,则把网关列表中其他网关标记为不是主网关 if (gw.GwId != id && oldHomeID == gw.HomeId) { gw.IsMainGateWay = false; } } //标记当前网关是主网关 gateWay.IsMainGateWay = true; } } //测试能否广播得到网关,通常情况下不检测 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.CheckCanReceiveGateway == 1) { if (Shared.Phone.UserCenter.UserCenterResourse.DicReceiveGatewayTest.ContainsKey(id) == false) { if (gateWay == null) { Shared.Phone.UserCenter.UserCenterResourse.DicReceiveGatewayTest[id] = zbGateWay; } else { Shared.Phone.UserCenter.UserCenterResourse.DicReceiveGatewayTest[id] = gateWay; } } } } } catch { //关闭Socket,下次发送会自动连接 FindGateWaySocket.Stop(); } } #endregion } catch { } System.Threading.Thread.Sleep(500); } }) { IsBackground = true }.Start(); ///远程主网关更新 new System.Threading.Thread(async () => { while (true) { try { //定时检测远程连接情况 await ZbGateway.StartRemoteMqtt(); } catch { } System.Threading.Thread.Sleep(2000); } }) { IsBackground = true }.Start(); } /// /// 重新搜索,注意:调用该方法,则促使全部网关的mqtt全部断开,然后重新搜索(可能会有1秒延迟) /// public static void ReSearch() { //为了那么多少万分之一的几率,这里设置成别的另一类的值 oldHomeID = "**"; } /// /// 接收处理UDP数据包 /// /// public static class FindGateWaySocket { //本地Socket public static Socket busSocket; /// /// 启动Socket接收和发送功能 /// /// public static void Start(int port = 7624) { if (IsRunning) { return; } //定义网络类型,数据连接类型和网络协议UDP busSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); busSocket.EnableBroadcast = true; busSocket.ReceiveTimeout = 1000; busSocket.SendTimeout = 1000; busSocket.Bind(new IPEndPoint(IPAddress.Any, port)); } /// /// 停止Socket /// public static void Stop() { if (!IsRunning) { return; } try { busSocket.Close(); } catch { } busSocket = null; Console.WriteLine("BusSocket关闭成功!"); } /// /// 当前的Socket是否运行 /// public static bool IsRunning { get { return busSocket == null ? false : true; } } /// /// 异步发送数据 /// /// public static void BeginSend(System.Net.IPEndPoint iPEndPoint, byte[] bytes) { try { Start(7624); busSocket.BeginSendTo(bytes, 0, bytes.Length, SocketFlags.None, iPEndPoint, new AsyncCallback(asyncEndSend), null); } catch { } } /// /// 异步发送数据结束 /// /// private static void asyncEndSend(IAsyncResult iar) { try { int bytesSent = busSocket.EndSendTo(iar); } catch { } } } } }