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