New file |
| | |
| | | /* |
| | | * 该类用于管理tcp作为服务端连接通讯 |
| | | */ |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Net.Sockets; |
| | | using System.Threading; |
| | | using System.Net; |
| | | using Shared; |
| | | using HDL_ON.Entity; |
| | | |
| | | namespace HDL_ON.DriverLayer |
| | | { |
| | | /// <summary> |
| | | /// TCP服务端 |
| | | /// </summary> |
| | | public class Control_TcpServer |
| | | { |
| | | private Socket ServerSocket = null;//服务端 |
| | | public Dictionary<string, MySession> dic_ClientSocket = new Dictionary<string, MySession>();//tcp客户端字典 |
| | | private Dictionary<string, Thread> dic_ClientThread = new Dictionary<string, Thread>();//线程字典,每新增一个连接就添加一条线程 |
| | | private bool Flag_Listen = true;//监听客户端连接的标志 |
| | | |
| | | /// <summary> |
| | | /// 启动服务 |
| | | /// </summary> |
| | | /// <param name="port">端口号</param> |
| | | public bool OpenServer(int port = 8586) |
| | | { |
| | | try |
| | | { |
| | | Flag_Listen = true; |
| | | // 创建负责监听的套接字,注意其中的参数; |
| | | ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
| | | // 创建包含ip和端口号的网络节点对象; |
| | | IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, port); |
| | | try |
| | | { |
| | | // 将负责监听的套接字绑定到唯一的ip和端口上; |
| | | ServerSocket.Bind(endPoint); |
| | | } |
| | | catch |
| | | { |
| | | return false; |
| | | } |
| | | // 设置监听队列的长度; |
| | | ServerSocket.Listen(100); |
| | | // 创建负责监听的线程; |
| | | Thread Thread_ServerListen = new Thread(ListenConnecting); |
| | | Thread_ServerListen.IsBackground = true; |
| | | Thread_ServerListen.Start(); |
| | | |
| | | MainPage.Log("启动tcp侦听"); |
| | | return true; |
| | | } |
| | | catch |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 关闭服务 |
| | | /// </summary> |
| | | public void CloseServer() |
| | | { |
| | | lock (dic_ClientSocket) |
| | | { |
| | | foreach (var item in dic_ClientSocket) |
| | | { |
| | | item.Value.Close();//关闭每一个连接 |
| | | } |
| | | dic_ClientSocket.Clear();//清除字典 |
| | | } |
| | | lock (dic_ClientThread) |
| | | { |
| | | foreach (var item in dic_ClientThread) |
| | | { |
| | | item.Value.Abort();//停止线程 |
| | | } |
| | | dic_ClientThread.Clear(); |
| | | } |
| | | Flag_Listen = false; |
| | | //ServerSocket.Shutdown(SocketShutdown.Both);//服务端不能主动关闭连接,需要把监听到的连接逐个关闭 |
| | | if (ServerSocket != null) |
| | | ServerSocket.Close(); |
| | | |
| | | } |
| | | /// <summary> |
| | | /// 监听客户端请求的方法; |
| | | /// </summary> |
| | | private void ListenConnecting() |
| | | { |
| | | while (Flag_Listen) // 持续不断的监听客户端的连接请求; |
| | | { |
| | | try |
| | | { |
| | | Socket sokConnection = ServerSocket.Accept(); // 一旦监听到一个客户端的请求,就返回一个与该客户端通信的 套接字; |
| | | // 将与客户端连接的 套接字 对象添加到集合中; |
| | | string str_EndPoint = sokConnection.RemoteEndPoint.ToString(); |
| | | MySession myTcpClient = new MySession() { TcpSocket = sokConnection }; |
| | | //创建线程接收数据 |
| | | Thread th_ReceiveData = new Thread(ReceiveData); |
| | | th_ReceiveData.IsBackground = true; |
| | | th_ReceiveData.Start(myTcpClient); |
| | | //把线程及客户连接加入字典 |
| | | dic_ClientThread.Add(str_EndPoint, th_ReceiveData); |
| | | dic_ClientSocket.Add(str_EndPoint, myTcpClient); |
| | | } |
| | | catch |
| | | { |
| | | |
| | | } |
| | | Thread.Sleep(200); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 接收数据 |
| | | /// </summary> |
| | | /// <param name="sokConnectionparn"></param> |
| | | private void ReceiveData(object sokConnectionparn) |
| | | { |
| | | MySession tcpClient = sokConnectionparn as MySession; |
| | | Socket socketClient = tcpClient.TcpSocket; |
| | | bool Flag_Receive = true; |
| | | |
| | | while (Flag_Receive) |
| | | { |
| | | try |
| | | { |
| | | // 定义一个2M的缓存区; |
| | | byte[] arrMsgRec = new byte[1024 * 1024 * 2]; |
| | | // 将接受到的数据存入到输入 arrMsgRec中; |
| | | int length = -1; |
| | | try |
| | | { |
| | | length = socketClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | MainPage.Log($"tcpListener error 1 : {ex.Message}"); |
| | | |
| | | Flag_Receive = false; |
| | | // 从通信线程集合中删除被中断连接的通信线程对象; |
| | | string keystr = socketClient.RemoteEndPoint.ToString(); |
| | | dic_ClientSocket.Remove(keystr);//删除客户端字典中该socket |
| | | dic_ClientThread[keystr].Abort();//关闭线程 |
| | | dic_ClientThread.Remove(keystr);//删除字典中该线程 |
| | | |
| | | tcpClient = null; |
| | | socketClient = null; |
| | | break; |
| | | } |
| | | byte[] buf = new byte[length]; |
| | | Array.Copy(arrMsgRec, buf, length); |
| | | lock (tcpClient.m_Buffer) |
| | | { |
| | | //tcpClient.m_Buffer.Add(buf); |
| | | var tcpDataString = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length); |
| | | if (!string.IsNullOrEmpty(tcpDataString)) |
| | | { |
| | | AnalysisTcpData(socketClient, tcpDataString); |
| | | } |
| | | |
| | | MainPage.Log(tcpDataString); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | MainPage.Log($"tcpListener error 2 : {ex.Message}"); |
| | | } |
| | | Thread.Sleep(100); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 获取列表数据回调方法 |
| | | /// </summary> |
| | | public Action<string> GetListResponseAction; |
| | | string tcpFunctionOidJsonString = ""; |
| | | /// <summary> |
| | | /// 处理tcp数据 |
| | | /// </summary> |
| | | void AnalysisTcpData(Socket socket, string tcpBodyDataString) |
| | | { |
| | | MainPage.Log($"0001 tcpDataString:\r\n {tcpBodyDataString}"); |
| | | var tcpDataObj = Control.Ins.AnalysisReceiveData(tcpBodyDataString); |
| | | if (tcpDataObj.BodyDataString == null) |
| | | { |
| | | return; |
| | | } |
| | | switch (tcpDataObj.Topic) |
| | | { |
| | | case CommunicationTopic.AddDeviceOids: |
| | | tcpFunctionOidJsonString = tcpDataObj.BodyDataString; |
| | | break; |
| | | case CommunicationTopic.AddFunctions: |
| | | var addSidFunction = Newtonsoft.Json.JsonConvert.DeserializeObject<TcpTransmissionSidsObj>(tcpDataObj.BodyDataString); |
| | | Application.RunOnMainThread(() => |
| | | { |
| | | var tipDialog = new UI.UpdataSidDataDialog(); |
| | | var tcpLocalFunction = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Function>>(Newtonsoft.Json.JsonConvert.SerializeObject(addSidFunction.objects)); |
| | | tipDialog.ShowDialog(tcpLocalFunction, tcpFunctionOidJsonString); |
| | | }); |
| | | break; |
| | | case CommunicationTopic.BusPcGetAppOids: |
| | | |
| | | var bytes = Common.FileUtlis.Files.ReadFile(DB_ResidenceData.OidSavePathName); |
| | | if (bytes.Length > 0) |
| | | { |
| | | socket.Send(bytes); |
| | | MainPage.Log($"send oid list to 8586 prot :{ System.Text.Encoding.UTF8.GetString(bytes)}"); |
| | | } |
| | | break; |
| | | case CommunicationTopic.BusPcGetAppSids: |
| | | var sendSidObj = new TcpTransmissionSidsObj(); |
| | | sendSidObj.id = Control.Ins.msg_id.ToString(); |
| | | sendSidObj.time_stamp = ""; |
| | | //转换成bus需要的数据格式 |
| | | var localFunction = FunctionList.List.GetDeviceFunctionList(); |
| | | var localFunctionString = Newtonsoft.Json.JsonConvert.SerializeObject(localFunction); |
| | | var tcpFunction = Newtonsoft.Json.JsonConvert.DeserializeObject<List<BusSidObj>>(localFunctionString); |
| | | |
| | | sendSidObj.objects.AddRange(tcpFunction); |
| | | var sendSidJson = Newtonsoft.Json.JsonConvert.SerializeObject(sendSidObj); |
| | | var sendSidBytes = System.Text.Encoding.UTF8.GetBytes(sendSidJson); |
| | | socket.Send(sendSidBytes, sendSidBytes.Length, SocketFlags.OutOfBand); |
| | | MainPage.Log($"send sid list to 8586 prot :{sendSidJson}"); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 发送数据给指定的客户端 |
| | | /// </summary> |
| | | /// <param name="_endPoint">客户端套接字</param> |
| | | /// <param name="_buf">发送的数组</param> |
| | | /// <returns></returns> |
| | | public bool SendData(string _endPoint, byte[] _buf) |
| | | { |
| | | MySession myT = new MySession(); |
| | | if (dic_ClientSocket.TryGetValue(_endPoint, out myT)) |
| | | { |
| | | myT.Send(_buf); |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 会话端 |
| | | /// </summary> |
| | | public class MySession |
| | | { |
| | | public Socket TcpSocket;//socket对象 |
| | | public List<byte> m_Buffer = new List<byte>();//数据缓存区 |
| | | |
| | | public MySession() |
| | | { |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 发送数据 |
| | | /// </summary> |
| | | /// <param name="buf"></param> |
| | | public void Send(byte[] buf) |
| | | { |
| | | if (buf != null) |
| | | { |
| | | TcpSocket.Send(buf); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 获取连接的ip |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public string GetIp() |
| | | { |
| | | IPEndPoint clientipe = (IPEndPoint)TcpSocket.RemoteEndPoint; |
| | | string _ip = clientipe.Address.ToString(); |
| | | return _ip; |
| | | } |
| | | /// <summary> |
| | | /// 关闭连接 |
| | | /// </summary> |
| | | public void Close() |
| | | { |
| | | TcpSocket.Shutdown(SocketShutdown.Both); |
| | | } |
| | | /// <summary> |
| | | /// 提取正确数据包 |
| | | /// </summary> |
| | | public byte[] GetBuffer(int startIndex, int size) |
| | | { |
| | | byte[] buf = new byte[size]; |
| | | m_Buffer.CopyTo(startIndex, buf, 0, size); |
| | | m_Buffer.RemoveRange(0, startIndex + size); |
| | | return buf; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 添加队列数据 |
| | | /// </summary> |
| | | /// <param name="buffer"></param> |
| | | public void AddQueue(byte[] buffer) |
| | | { |
| | | m_Buffer.AddRange(buffer); |
| | | } |
| | | /// <summary> |
| | | /// 清除缓存 |
| | | /// </summary> |
| | | public void ClearQueue() |
| | | { |
| | | m_Buffer.Clear(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// bus软件传输功能的sid列表对象 |
| | | /// </summary> |
| | | public class TcpTransmissionSidsObj |
| | | { |
| | | public List<BusSidObj> objects = new List<BusSidObj>(); |
| | | |
| | | public string id = ""; |
| | | public string time_stamp = ""; |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// bus软件传输的功能对象 |
| | | /// 仅在与bus软件传递数据时使用, |
| | | /// Function对象包含了该对象的所有内容, |
| | | /// 此对象为了减少传输数据使用 |
| | | /// </summary> |
| | | public class BusSidObj |
| | | { |
| | | public string sid = "";// "0301011234567801012301230123"; |
| | | |
| | | /// <summary> |
| | | /// A协议功能的属性 |
| | | /// 如:是AC功能:属性:on_off,mode,fan,temperature |
| | | /// </summary> |
| | | public List<FunctionAttributes> attributes = new List<FunctionAttributes>(); |
| | | |
| | | /// <summary> |
| | | /// 备注 |
| | | /// </summary> |
| | | public string name; |
| | | |
| | | public string omodel; |
| | | |
| | | } |
| | | |
| | | } |