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 { #region ■ 变量声明___________________________ public static bool isInited; /// /// 是否正在搜索网关 /// public static bool IsSearchingGateway = false; /// /// 上一次的住宅ID /// private static string oldHomeID = string.Empty; /// /// 接收的IP /// private static List listReceiveIP = new List(); #endregion #region ■ 初始化_____________________________ public static void Init() { if (isInited) { return; } isInited = true; //初始化Socket FindGateWaySocket.Start(); //发送广播数据 StartSendBroadcastData(); //接收广播数据 StartReceiveBroadcastData(); ///开启远程连接 StartRemoteMqtt(); } #endregion #region ■ 发送广播数据_______________________ /// /// 发送广播数据 /// private static void StartSendBroadcastData() { new System.Threading.Thread(() => { var searchCount = 3; 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 (CheckCanSendBroadcast(broadBytes) == false) { continue; } var broadcastIpAddress = new Shared.Net.NetWiFi().BroadcastIpAddress; if (Shared.Application.IsWifi) { if (0 < listReceiveIP.Count) { searchCount = 3; 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"); } //非wifi情况下,不需要广播 System.Threading.Thread.Sleep(1000); continue; } searchCount--; //每秒广播发现一次网关 int count = 2; listReceiveIP.Clear(); while (0 < count--) { //点对点发送(先发一条已有的点播,回复几率高一点) for (int i = 0; i < listReceiveIP.Count; i++) { FindGateWaySocket.BeginSend(new System.Net.IPEndPoint(System.Net.IPAddress.Parse(listReceiveIP[i]), 7624), broadBytes); } //广播发送 if (broadcastIpAddress.ToString() != "0.0.0.0") { FindGateWaySocket.BeginSend(new System.Net.IPEndPoint(broadcastIpAddress, 7624), broadBytes); } System.Threading.Thread.Sleep(1000); } } catch { } } }) { IsBackground = true }.Start(); } #endregion #region ■ 接收广播数据_______________________ /// /// 接收广播数据 /// private static void StartReceiveBroadcastData() { //数据接收 new System.Threading.Thread(async () => { while (true) { try { if (FindGateWaySocket.udpClient == null || FindGateWaySocket.udpClient.Available <= 0) { System.Threading.Thread.Sleep(500); continue; } var ipEndPoint = new System.Net.IPEndPoint(0, 0); var bytes = FindGateWaySocket.udpClient.Receive(ref ipEndPoint); 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 (listReceiveIP.Find(obj => obj == zbGateWay.GwId) == null) { //网关匹配当前住宅中到网关 if (Shared.Common.Config.Instance.HomeId == homeID) { listReceiveIP.Add(ipAddress); } //UI界面正在搜索,不必配当前住宅到到网关此时也通讯 else if (IsSearchingGateway) { listReceiveIP.Add(ipAddress); } //2020.08.07追加:即使空的住宅id也建立链接,对应手动恢复网关出厂设置时,因为没有解绑,但是住宅id为空的问题 else if (Shared.Phone.UserCenter.HdlGatewayLogic.Current.HomeIdIsEmpty(homeID) == true) { listReceiveIP.Add(ipAddress); } } //网关列表存储处理 var gateWay = ZbGateway.GateWayList.Find(obj => obj.GwId == zbGateWay.GwId); if (gateWay == null) { ZbGateway.GateWayList.Add(zbGateWay); await zbGateWay.StartLocalMqtt(ipAddress); } 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 == null) { //防止异常,虽然几率很低 Shared.Phone.UserCenter.UserCenterResourse.HideOption.CheckCanReceiveGateway = 0; continue; } 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; } } } } else { //调试用 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1) { var data33 = Encoding.UTF8.GetString(bytes).Replace("�)", string.Empty).TrimStart('\0').TrimEnd('\0'); Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, data33); } } } catch (Exception ex) { //调试用 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1) { Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "Receive异常\r\n" + ex.Message); } } } }) { IsBackground = true }.Start(); } #endregion #region ■ 开启远程连接_______________________ /// /// 开启远程连接 /// private static void StartRemoteMqtt() { new System.Threading.Thread(async () => { while (true) { try { //定时检测远程连接情况 await ZbGateway.StartRemoteMqtt(); } catch { } System.Threading.Thread.Sleep(2000); } }) { IsBackground = true }.Start(); } #endregion #region ■ 一般方法___________________________ /// /// 重新搜索,注意:调用该方法,则促使全部网关的mqtt全部断开,然后重新搜索(可能会有1秒延迟) /// public static void ReSearch() { //为了那么多少万分之一的几率,这里设置成别的另一类的值 oldHomeID = "**"; } /// /// 检测能否发送广播 /// /// private static bool CheckCanSendBroadcast(byte[] broadBytes) { if (string.IsNullOrEmpty(Config.Instance.HomeId)) { //住宅ID为空只有一种可能就是退出了登录,这里的上一次住宅ID要清空 oldHomeID = "?"; System.Threading.Thread.Sleep(1000); return false; } //首次进入网关,和切换住宅会清除网关列表,重新搜索存储 if (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 = Config.Instance.HomeId; ZbGateway.GateWayList.Add(gateWay); } } } return true; } #endregion #region ■ Socket_____________________________ /// /// 接收处理UDP数据包 /// /// public static class FindGateWaySocket { //本地Socket public static UdpClient udpClient; /// /// 启动Socket接收和发送功能 /// /// public static void Start() { if (udpClient!=null) { return; } udpClient = new UdpClient { EnableBroadcast = true }; } /// /// 停止Socket /// public static void Stop() { try { udpClient?.Close(); } catch { } udpClient = null; Console.WriteLine("BusSocket关闭成功!"); } /// /// 异步发送数据 /// /// public static void BeginSend(System.Net.IPEndPoint iPEndPoint, byte[] bytes) { try { if (udpClient == null) { return; } udpClient.Send(bytes, bytes.Length, iPEndPoint); } catch (Exception ex) { //调试用 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1) { Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "发送异常(BeginSendTo)\r\n" + ex.Message); } } } } #endregion } }