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; /// /// 发送的时间间隔(单位:秒) /// public static int SendTime = 3; /// /// 上一次的住宅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 broadBytes = new byte[44]; var waitCount = 0; while (true) { try { //检测能否发送广播 0:不能发送广播 1:可以发送广播 2:住宅ID变更 int result = CheckCanSendBroadcast(); if (result == 0) { continue; } if (result == 2) { //重新初始化广播数据 broadBytes = new byte[44]; broadBytes[0] = 0xfe; broadBytes[1] = 0x29; broadBytes[2] = 0x00; broadBytes[3] = 0x00; broadBytes[4] = 0x00; broadBytes[5] = 0x00; broadBytes[6] = 0x00; broadBytes[43] = 0x02; var tempBytes = System.Text.Encoding.UTF8.GetBytes(oldHomeID); System.Array.Copy(tempBytes, 0, broadBytes, 7, 36 < tempBytes.Length ? 36 : tempBytes.Length); } var broadcastIpAddress = new Shared.Net.NetWiFi().BroadcastIpAddress; //清空接收到的IP listReceiveIP.Clear(); if (broadcastIpAddress.ToString() != "0.0.0.0") { //广播出去 FindGateWaySocket.BeginSend(new System.Net.IPEndPoint(broadcastIpAddress, 7624), broadBytes); } //等待3秒,下面的接收方法会去接收广播 System.Threading.Thread.Sleep(SendTime * 1000); if (listReceiveIP.Count > 0) { waitCount = 0; //局域网能够广播得到网关 ZbGateway.IsRemote = false; //当网关的连接方式改变时,记录当前的连接方式 Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.WIFI); } else { waitCount++; if (waitCount >= 2) { //两次都搜不到,才标记为远程 continue; } waitCount = 0; //局域网广播不到网关 ZbGateway.IsRemote = true; //当网关的连接方式改变时,记录当前的连接方式 Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.Remote); } } 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(IPAddress.Any, 0); var bytes = FindGateWaySocket.udpClient.Receive(ref ipEndPoint); if (bytes.Length > 43 && 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, 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) { //刷新网关的在线时间点 Shared.Phone.UserCenter.HdlGatewayLogic.Current.RefreshGatewayOnlineTime(zbGateWay.GwId); ZbGateway.GateWayList.Add(zbGateWay); await zbGateWay.StartLocalMqtt(ipAddress); } else { //刷新网关的在线时间点 Shared.Phone.UserCenter.HdlGatewayLogic.Current.RefreshGatewayOnlineTime(gateWay.GwId); gateWay.IsVirtual = false; 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); } } await System.Threading.Tasks.Task.Delay(20); } 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 = "**"; } /// /// 检测能否发送广播(0:不能发送广播 1:可以发送广播 2:住宅ID变更) /// /// private static int CheckCanSendBroadcast() { if (string.IsNullOrEmpty(Config.Instance.HomeId)) { //住宅ID为空只有一种可能就是退出了登录,这里的上一次住宅ID要清空 oldHomeID = "?"; System.Threading.Thread.Sleep(1000); return 0; } //首次进入网关,和切换住宅会清除网关列表,重新搜索存储 if (Config.Instance.HomeId == oldHomeID) { return 1; } //因为那一瞬间,有可能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(); //住宅中已经存在的网关如果局域网不存在,需要在当前住宅中虚拟一个网关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); } } //住宅ID变更 oldHomeID = Config.Instance.HomeId; return 2; } #endregion #region ■ Socket_____________________________ /// /// 接收处理UDP数据包 /// /// public static class FindGateWaySocket { //本地Socket public static UdpClient udpClient; /// /// 启动Socket接收和发送功能 /// /// public static bool Start() { if (udpClient != null) { return true; } //获取手机的wifi地址 #if Android var netwifi = new Shared.Net.NetWiFi(); string phoneIp = netwifi.GetIPAddress(); #endif #if iOS string phoneIp = Shared.Net.NetWiFi.GetIPAddress(); #endif //"127.0.0.1"是底层库里面设置的初始默认值 if (phoneIp != "127.0.0.1") { udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(phoneIp), 7624)); udpClient.EnableBroadcast = true; return true; } return false; } /// /// 停止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 (Start() == false) { //调试用 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1) { Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "udp New不起来"); } return; } int value = udpClient.Send(bytes, bytes.Length, iPEndPoint); //调试用 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1) { Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "发送长度(BeginSendTo):" + value + " 发送内容:" + System.Text.Encoding.UTF8.GetString(bytes)); } } catch (Exception ex) { //调试用 if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1) { Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "发送异常(BeginSendTo)\r\n" + ex.Message); } } } } #endregion } }