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 { }
}
}
}
}