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;
|
/// <summary>
|
/// 是否正在搜索网关
|
/// </summary>
|
public static bool IsSearchingGateway = false;
|
/// <summary>
|
/// 新发现的网关通知
|
/// </summary>
|
public static Action<ZigBee.Device.ZbGateway> NewGateWayAction;
|
/// <summary>
|
/// 上一次的住宅ID
|
/// </summary>
|
private static string oldHomeID = string.Empty;
|
|
public static void Init()
|
{
|
if (isInited)
|
{
|
return;
|
}
|
isInited = true;
|
|
//初始化Socket
|
FindGateWaySocket.Start();
|
|
new System.Threading.Thread(async () =>
|
{
|
var gateWayList = new List<ZbGateway> { };
|
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<ZbGateway>();
|
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{}
|
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;
|
}
|
}
|
}
|
}
|
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{}
|
}
|
#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();
|
}
|
|
/// <summary>
|
/// 重新搜索,注意:调用该方法,则促使全部网关的mqtt全部断开,然后重新搜索(可能会有1秒延迟)
|
/// </summary>
|
public static void ReSearch()
|
{
|
//为了那么多少万分之一的几率,这里设置成别的另一类的值
|
oldHomeID = "**";
|
}
|
|
/// <summary>
|
/// 接收处理UDP数据包
|
/// </summary>
|
/// <typeparam name="T"></typeparam>
|
public static class FindGateWaySocket
|
{
|
//本地Socket
|
public static Socket busSocket;
|
|
/// <summary>
|
/// 启动Socket接收和发送功能
|
/// </summary>
|
/// <param name="port"></param>
|
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));
|
}
|
|
/// <summary>
|
/// 停止Socket
|
/// </summary>
|
public static void Stop()
|
{
|
if (!IsRunning)
|
{
|
return;
|
}
|
try
|
{
|
busSocket.Close();
|
}
|
catch { }
|
busSocket = null;
|
|
Console.WriteLine("BusSocket关闭成功!");
|
}
|
|
/// <summary>
|
/// 当前的Socket是否运行
|
/// </summary>
|
public static bool IsRunning
|
{
|
get
|
{
|
return busSocket == null ? false : true;
|
}
|
}
|
|
/// <summary>
|
/// 异步发送数据
|
/// </summary>
|
/// <param name="tempPacket"></param>
|
public static void BeginSend(System.Net.IPEndPoint iPEndPoint, byte[] bytes)
|
{
|
try
|
{
|
if (IsRunning)
|
{
|
busSocket.BeginSendTo(bytes, 0, bytes.Length, SocketFlags.None, iPEndPoint, new AsyncCallback(asyncEndSend), null);
|
}
|
|
}
|
catch (Exception ex)
|
{
|
//调试用
|
if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1)
|
{
|
Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "发送异常(BeginSendTo)\r\n" + ex.Message);
|
}
|
}
|
}
|
|
/// <summary>
|
/// 异步发送数据结束
|
/// </summary>
|
/// <param name="iar"></param>
|
private static void asyncEndSend(IAsyncResult iar)
|
{
|
try
|
{
|
int bytesSent = busSocket.EndSendTo(iar);
|
}
|
catch(Exception ex)
|
{
|
//调试用
|
if (Shared.Phone.UserCenter.UserCenterResourse.HideOption.WriteSocketReceiveDataToFile == 1)
|
{
|
Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(3, "异步发送结束异常(asyncEndSend)\r\n" + ex.Message);
|
}
|
}
|
}
|
}
|
}
|
}
|