需求:想在开发的应用中加一个简单的后台控制,并向服务器发送该设备基本信息(公网ip,机器码,等);在服务器控制该设备是否可以正常打开该应用。
已实现功能:每个每个应用(客户端)向服务端发送设备信息等数据。服务器端对数据处理后存储到服务器本地JSON里。客户端打开是要判断服务器是否禁止该设备使用。服务器端JSON文件可以查看该应用每个用户使用次数和打开时间等。(实现一个简单的远程控制)。
待实现功能:判断用户单次使用时间并写入JSON
客户端:发送设备信息到服务器。
服务端:用来接收客户端数据,并且存储json到服务器。
使用socket来写。
客户端代码:
using UnityEngine;
using UnityEngine.UI;
using System.Net;
using System.Net.Sockets;//引入socket命名空间
using System.Threading;
using System.Text;
using UnityEngine.SceneManagement;
using System.IO;
using System.Net.NetworkInformation;
using System;
using System.Collections;
using UnityEngine.Networking;
using System.Collections.Generic;
using Newtonsoft.Json;
#region json格式解析
[Serializable]
public class Info
{
public string DeviceCode;
public string Ip;
public string productName;
public string DeviceInfo;
public List<string> time;
public int count;
public string Switch;
}
#endregion
public class Client : MonoBehaviour
{
public Text text;//在屏幕上显示出设备信息
public string path;//Json文件在服务器上的路径
void Start()
{
//连接服务器
ConnectServer();
#region 显示设备信息
string info = "设备的详细信息" +
"\n设备名称: " + SystemInfo.deviceName
+ "\nCPU类型:" + SystemInfo.processorType
+ "\n" + "设备唯一识别标识:" + SystemInfo.deviceUniqueIdentifier
+ "\n" + "显卡名称:" + SystemInfo.graphicsDeviceName
+ "\n显卡厂商:" + SystemInfo.graphicsDeviceVendor
+ "\n" + "操作系统:" + SystemInfo.operatingSystem
+ "\n" + "MAC地址:" + GetMacAddress()
+ "\n" + "公网IP:" + GetIp("http://104.16.22.1/cdn-cgi/trace");
text.text = info;
#endregion
StartCoroutine(GetData());
}
/// <summary>
/// 此协程用来判断服务器存的字典中是否禁止此设备运行本软件
/// </summary>
/// <returns></returns>
IEnumerator GetData()
{
UnityWebRequest www = UnityWebRequest.Get(path);
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
var ip = www.downloadHandler.text.ToString();
Dictionary<string, Info> root = new Dictionary<string, Info>();
root = JsonConvert.DeserializeObject<Dictionary<string, Info>>(ip);//解析json
if (root.ContainsKey(SystemInfo.deviceUniqueIdentifier))//字典中是否存在此设备
{
if (root[SystemInfo.deviceUniqueIdentifier].Switch == "关")//判断是否关闭应用
{
Application.Quit();
}
}
}
}
/// <summary>
/// 连接服务器
/// </summary>
static Socket socket_client;
public static void ConnectServer()
{
try
{
IPAddress pAddress = IPAddress.Parse("服务器公网IP"); //如果是本地就写本地ipv4地址
IPEndPoint pEndPoint = new IPEndPoint(pAddress, 服务器端口号);
socket_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket_client.Connect(pEndPoint);
Debug.Log("连接成功");
string info = "设备的详细信息:" +
"设备名称: " + SystemInfo.deviceName
+ "——CPU类型:" + SystemInfo.processorType
+ "——" + "设备唯一识别标识:" + SystemInfo.deviceUniqueIdentifier
+ "——" + "显卡名称:" + SystemInfo.graphicsDeviceName
+ "——显卡厂商:" + SystemInfo.graphicsDeviceVendor
+ "——" + "操作系统:" + SystemInfo.operatingSystem
+ "——" + "MAC地址:" + GetMacAddress()
+ "——" + "公网IP:" + GetIp("http://104.16.22.1/cdn-cgi/trace");
Send(SystemInfo.deviceUniqueIdentifier + "_" + GetIp("http://104.16.22.1/cdn-cgi/trace")+"_"+ Application.productName+Application.version + "_" + info);
//创建线程,执行读取服务器消息
Thread c_thread = new Thread(Received);
c_thread.IsBackground = true;
c_thread.Start();
}
catch (System.Exception)
{
Debug.Log("IP端口号错误或者服务器未开启");
}
}
/// <summary>
/// 读取服务器消息
/// </summary>
public static void Received()
{
while (true)
{
try
{
byte[] buffer = new byte[1024];
int len = socket_client.Receive(buffer);
if (len == 0) break;
string str = Encoding.UTF8.GetString(buffer, 0, len);
Debug.Log("客户端打印服务器返回消息:" + socket_client.RemoteEndPoint + ":" + str);
}
catch (System.Exception)
{
throw;
}
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="msg"></param>
public static void Send(string msg)
{
try
{
byte[] buffer = new byte[1024];
buffer = Encoding.UTF8.GetBytes(msg);
socket_client.Send(buffer);
}
catch (System.Exception)
{
Debug.Log("未连接");
}
}
/// <summary>
/// 关闭连接
/// </summary>
public static void close()
{
try
{
socket_client.Close();
Debug.Log("关闭客户端连接");
SceneManager.LoadScene("control");
}
catch (System.Exception)
{
Debug.Log("未连接");
}
}
private void OnDestroy()
{
close();
}
/// <summary>
/// 获取公网ip
/// </summary>
/// <param name="ipurl"></param>
/// <returns></returns>
public static string GetIp(string ipurl)
{
UnityWebRequest request = UnityWebRequest.Get(ipurl);
request.SendWebRequest();//读取数据
while (true)
{
if (request.downloadHandler.isDone)//是否读取完数据
{
var ip = request.downloadHandler.text.ToString().Substring(request.downloadHandler.text.IndexOf("ip=") + 3, request.downloadHandler.text.IndexOf("ts=") - request.downloadHandler.text.IndexOf("ip=") - 4);
return ip;
}
}
}
/// <summary>
/// 获取设备MAC地址
/// </summary>
/// <returns></returns>
private static string GetMacAddress()
{
//MAC 地址字符串
string _PhysicalAddress = "";
//获取所有网络接口
NetworkInterface[] _Nice = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface _Adaper in _Nice)
{
//得到物理地址
_PhysicalAddress = _Adaper.GetPhysicalAddress().ToString();
if (_PhysicalAddress != "")
{
break;
};
}
return _PhysicalAddress;
}
}
服务端代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;//需要引用socket命名空间
using System.Net;
using System.Linq;
using System.Text;
using System.Threading;
using UnityEngine.UI;
using System.IO;
using System;
using Newtonsoft.Json;
#region json格式解析
[Serializable]
public class Info
{
public string DeviceCode;
public string Ip;
public string productName;
public string DeviceInfo;
public List<string> time;
public int count;
public string Switch;
}
#endregion
public class Server : MonoBehaviour
{
public List<string> logs;
public Text text;//显示log
public string m_IP;//服务器ip(内网)
public string m_Path;//服务器json文件路径
void Start()
{
openServer();
}
/// <summary>
/// 解析json文件
/// </summary>
/// <returns></returns>
Dictionary<string, Info> LoadJson()
{
Dictionary<string, Info> root = new Dictionary<string, Info>();
if (File.Exists(m_Path))
{
root = JsonConvert.DeserializeObject<Dictionary<string, Info>>(File.ReadAllText(m_Path));
}
return root;
}
/// <summary>
/// 处理数据
/// </summary>
/// <param name="obj">客户端发来的数据</param>
public void DataDiapose(object obj)
{
Dictionary<string, Info> dic = LoadJson();
List<string> times = new List<string>();
Loom.QueueOnMainThread((param) =>
{
Info info = new Info();
info.DeviceCode = obj.ToString().Split('_')[0];
info.Ip = obj.ToString().Split('_')[1];
info.productName = obj.ToString().Split('_')[2];
info.DeviceInfo = obj.ToString().Split('_')[3];
times.Add(DateTime.Now.ToString());
info.time= times;
info.count = 1;
if (!dic.ContainsKey(info.DeviceCode))//如果json中没有该设备的信息,存入
{
dic.Add(info.DeviceCode, info);
}
else
{
//如果有就加入本次打开时间并增加使用次数
dic[info.DeviceCode].time.Add(DateTime.Now.ToString());
dic[info.DeviceCode].count += 1;
}
WriteJson(dic); //把新数据写入json
}, null);
}
/// <summary>
/// 写入json
/// </summary>
/// <param name="info"></param>
public void WriteJson(Dictionary<string, Info> info)
{
if (File.Exists(m_Path))
{
File.Delete(m_Path);
}
Debug.Log(m_Path);
//找到当前路径
FileInfo fileInfo = new FileInfo(m_Path);
//判断有没有文件,有则打开,没有则创建后打开
StreamWriter sw = fileInfo.CreateText();
//ToJson接口将你的列表类传进去,转为string
string json = JsonConvert.SerializeObject(info);
//将转换好的字符串保存到文件
sw.WriteLine(json);
//释放资源
sw.Close();
sw.Dispose();
}
//在text上刷新显示log
public void MyLog(object lg)
{
Loom.QueueOnMainThread((param) =>
{
if (logs.Count >= 10)
{
logs.RemoveAt(0);
}
logs.Add(lg.ToString());
text.text = "";
foreach (var item in logs)
{
text.text += item + "\n";
}
}, null);
}
/// <summary>
/// 打开链接
/// </summary>
void openServer()
{
try
{
IPAddress pAddress = IPAddress.Parse(m_IP);
IPEndPoint pEndPoint = new IPEndPoint(pAddress, 12345);
Socket socket_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket_server.Bind(pEndPoint);
socket_server.Listen(5);//设置最大连接数
Debug.Log("监听成功");
Loom.RunAsync(
() =>
{
ParameterizedThreadStart ParStart1 = new ParameterizedThreadStart(MyLog);
Thread thread2 = new Thread(ParStart1);
object o = " 监听成功 ";
thread2.Start(o);
}
);
//创建新线程执行监听,否则会阻塞UI,导致unity无响应
Thread thread = new Thread(listen);
thread.IsBackground = true;
thread.Start(socket_server);
}
catch (System.Exception)
{
throw;
}
}
/// <summary>
/// 监听
/// </summary>
Socket socketSend;
void listen(object o)
{
try
{
Socket socketWatch = o as Socket;
while (true)
{
socketSend = socketWatch.Accept();
string tempStr = socketSend.RemoteEndPoint.ToString() + ":" + "连接成功";
Debug.Log(tempStr);
Loom.RunAsync(
() =>
{
ParameterizedThreadStart ParStart1 = new ParameterizedThreadStart(MyLog);
Thread thread2 = new Thread(ParStart1);
object oo = tempStr;
thread2.Start(oo);
}
);
Thread r_thread = new Thread(Received);
r_thread.IsBackground = true;
r_thread.Start(socketSend);
}
}
catch (System.Exception)
{
throw;
}
}
/// <summary>
/// 获取消息
/// </summary>
/// <param name="o"></param>
void Received(object o)
{
try
{
Socket socketSend = o as Socket;
while (true)
{
byte[] buffer = new byte[1024];
int len = socketSend.Receive(buffer);
if (len == 0) break;
string str = Encoding.UTF8.GetString(buffer, 0, len);
string tempStr = "服务器打印客户端返回消息:" + socketSend.RemoteEndPoint + ":" + DateTime.Now+"登录";
Debug.Log(tempStr);
Loom.RunAsync(
() =>
{
ParameterizedThreadStart ParStart = new ParameterizedThreadStart(DataDiapose);
Thread thread2 = new Thread(ParStart);
object o2 = str;
thread2.Start(o2);
}
);
Loom.RunAsync(
() =>
{
ParameterizedThreadStart ParStart1 = new ParameterizedThreadStart(MyLog);
Thread thread2 = new Thread(ParStart1);
object oo = tempStr;
thread2.Start(oo);
}
);
//Send("我收到了");
}
}
catch (System.Exception)
{
throw;
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="msg"></param>
void Send(string msg)
{
byte[] buffer = Encoding.UTF8.GetBytes(msg);
socketSend.Send(buffer);
}
}
效果:
工程:下载链接
直接打开两个项目或分别将以下两个unitypackage包导入项目