using System; using System.Collections.Concurrent; using System.ComponentModel.Design; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using TouchSocket.Core; using TouchSocket.Sockets; using WCS.BLL.Tool; namespace WCS.BLL { /// /// 对TouchSocket的封装 主要完成TCP的连接 状态更新 发送接收通信 /// public class TCPClient { public string RemoteIPHost { get; set; } = "127.0.0.1:20002"; public string BindIPHost { get; set; } = "127.0.0.1:20003"; public string ShelfTypeName { get; set; } public bool IsReceivedClientOnline { get; set; } = false; public bool IsSendClientOnline { get; set; } = false; //第一次连接是否已连接 public bool IsFirstConnected { get; set; } = false; //can模块协议前缀 public readonly byte[] Prefix = new byte[] { 0x08, 0x00, 0x00 }; //can模块协议前缀长度 public readonly int PreFixLength = 3; //协议数据部分长度 public readonly int DataLength = 10; public TcpClient tcpSendClient { get; set; } //同步发送等待客户端 等待上一条指令发送成功并收到响应之后才发送下一条指令 public IWaitingClient waitClient; public TcpClient tcpReceiveClient { get; set; } public object receivdLockObject = new object(); public object sendLockObject = new object(); public bool Connect() { try { tcpSendClient.Connect();//调用连接,当连接不成功时,会抛出异常。 tcpReceiveClient.Connect(); return true; } catch (Exception e) { //连接失败 return false; } } /// /// 初始化配置连接 /// /// public TCPClient(string remoteIPHost, string bindIPHost, string shelfTypeName) { try { RemoteIPHost = remoteIPHost; BindIPHost = bindIPHost; ShelfTypeName = shelfTypeName; tcpSendClient = new TcpClient(); tcpReceiveClient = new TcpClient(); if (string.IsNullOrEmpty(BindIPHost)) { //载入配置 tcpSendClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(RemoteIPHost)) .ConfigurePlugins(a => { //配置断线重连 a.UseReconnection(-1, true, 1000); a.Add(); }) .ConfigureContainer(a => { //添加控制台日志注入 a.AddConsoleLogger(); })); waitClient = tcpSendClient.CreateWaitingClient(new WaitingOptions() { FilterFunc = response => //设置用于筛选的fun委托,当返回为true时,才会响应返回 { if (response.Data.Length == 13) { return true; } return false; } }); tcpReceiveClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(RemoteIPHost)) //.SetBindIPHost(BindIPHost) .ConfigurePlugins(a => { //配置断线重连 a.UseReconnection(-1, true, 1000); a.Add(); }) .ConfigureContainer(a => { //添加控制台日志注入 a.AddConsoleLogger(); })); } else { //载入配置 tcpSendClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(RemoteIPHost)) .SetBindIPHost(new IPHost(BindIPHost)) .ConfigurePlugins(a => { //配置断线重连 a.UseReconnection(-1, true, 1000); a.Add(); }) .ConfigureContainer(a => { //添加控制台日志注入 a.AddConsoleLogger(); })); waitClient = tcpSendClient.CreateWaitingClient(new WaitingOptions() { FilterFunc = response => //设置用于筛选的fun委托,当返回为true时,才会响应返回 { if (response.Data.Length == 13) { return true; } return false; } }); tcpReceiveClient.Setup(new TouchSocketConfig() .SetRemoteIPHost(new IPHost(RemoteIPHost)) //.SetBindIPHost(BindIPHost) .ConfigurePlugins(a => { //配置断线重连 a.UseReconnection(-1, true, 1000); a.Add(); }) .ConfigureContainer(a => { //添加控制台日志注入 a.AddConsoleLogger(); })); } //添加接收事件 匹配已发送的指令 //tcpReceiveClient.Received += (client, e) => //{ // var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray(); // Task.Run(() => // { // Logs.Write($"【校验发送接收 开始】{ShelfTypeName}" + BitConverter.ToString(data), LogsType.InstructionResend); // if (ShelfTypeName == "信息化货架") // { // //协议拆包 // var len = data.Length; // //灯控制统一返回的是 FF-00-00-0A-00-02-D7-B5 // if (len == 8) // { // if (data[4] == 0x00 && data[0] == 0xFF && data[1] == 0x00 && (data[5] == 0x01 || data[5] == 0x02)) // { // } // } // } // else if (ShelfTypeName == "液晶标签货架") // { // Logs.Write($"【液晶标签货架】接收到指令{BitConverter.ToString(data)}", LogsType.InstructionResend); // } // //智能货架 // else // { // var len = data.Length; // for (int index = 0; index < data.Length - PreFixLength; index++) // { // //协议拆包 通过前缀校验是否为完整数据包 // var prefixInData = data.Skip(index).Take(PreFixLength); // var isEqual = prefixInData.SequenceEqual(Prefix); // if (isEqual) // { // var dataTemp = data.Skip(index).Take(PreFixLength + DataLength).ToArray(); // if (dataTemp.Length < PreFixLength + DataLength)//拆包后不满足一条指令的长度 // { // continue; // } // //获取返回指令的板子ID // var boardId = (dataTemp[PreFixLength + 0] << 8) + dataTemp[PreFixLength + 1]; // index += (PreFixLength + DataLength - 2);//每次循环index会+1 所以这里-1 // } // } // } // Logs.Write($"【校验发送接收 结束】{ShelfTypeName}" + BitConverter.ToString(data), LogsType.InstructionResend); // }); // return null; //}; tcpSendClient.Connected += (client, e) => { this.IsSendClientOnline = true; return EasyTask.CompletedTask; }; tcpSendClient.Disconnected += (client, e) => { this.IsSendClientOnline = false; return EasyTask.CompletedTask; }; tcpReceiveClient.Connected += (client, e) => { this.IsReceivedClientOnline = true; return EasyTask.CompletedTask; }; tcpReceiveClient.Disconnected += (client, e) => { this.IsReceivedClientOnline = false; ReConnectAsync(); return EasyTask.CompletedTask; }; } catch (Exception ex) { } } public void ReConnectAsync() { if (IsSendClientOnline == false) tcpSendClient.TryConnectAsync(); if (IsReceivedClientOnline == false) tcpReceiveClient.TryConnectAsync(); } public void Send(byte[] message, bool IsReSend = false) { try { var boardId = (message[3] << 8) + message[4]; lock (sendLockObject) { tcpReceiveClient.Send(message); var clientIpHost = tcpReceiveClient.IP + ":" + tcpReceiveClient.Port; Logs.Write($"【发送{clientIpHost}】{BitConverter.ToString(message)}", LogsType.Instructions); //发送自带10ms间隔 Thread.Sleep(10); } } catch (Exception ex) { Logs.Write("【发送指令时发生异常】" + ex.Message, LogsType.Instructions); //因异常断连时(网线已经被断了) 手动重连一次 if (ex is NotConnectedException) { IsReceivedClientOnline = false; Task.Run(() => { ReConnectAsync(); }); } throw ex; } } public void SendList(List messages, bool IsReSend = false) { try { lock (sendLockObject) { foreach (var message in messages) { var clientIpHost = tcpSendClient.IP + ":" + tcpSendClient.Port; Logs.Write($"【发送{clientIpHost}】{BitConverter.ToString(message)}", LogsType.Instructions); tcpReceiveClient.Send(message); Thread.Sleep(3); } } } catch (Exception ex) { Logs.Write("【发送指令时发生异常】" + ex.Message, LogsType.Instructions); //因异常断连时(网线已经被断了) 手动重连一次 if (ex is NotConnectedException) { IsReceivedClientOnline = false; Task.Run(() => { ReConnectAsync(); }); } throw ex; } } public void SendThenReturn(byte[] message, bool IsReSend = false) { try { lock (sendLockObject) { var clientIpHost = tcpSendClient.IP + ":" + tcpSendClient.Port; Logs.Write($"【同步等待发送{clientIpHost}】{BitConverter.ToString(message)}", LogsType.Instructions); waitClient.SendThenReturn(message); Thread.Sleep(3); } } catch (Exception ex) { Logs.Write("【同步等待发送指令时发生异常】" + ex.Message, LogsType.Instructions); //因异常断连时(网线已经被断了) 手动重连一次 if (ex is NotConnectedException) { IsSendClientOnline = false; Task.Run(() => { ReConnectAsync(); }); } throw ex; } } public void SendThenReturnList(List messages, bool IsReSend = false) { try { lock (sendLockObject) { foreach (var message in messages) { var clientIpHost = tcpSendClient.IP + ":" + tcpSendClient.Port; Logs.Write($"【同步等待发送{clientIpHost}】{BitConverter.ToString(message)}", LogsType.Instructions); waitClient.SendThenReturn(message); Thread.Sleep(3); } } } catch (Exception ex) { Logs.Write("【同步等待发送指令时发生异常】" + ex.Message, LogsType.Instructions); //因异常断连时(网线已经被断了) 手动重连一次 if (ex is NotConnectedException) { IsSendClientOnline = false; Task.Run(() => { ReConnectAsync(); }); } throw ex; } } //生成协议明细 public byte[] GenerateMessage(int boardId, byte[] data) { var message = new byte[Prefix.Length + 2 + data.Length]; var boardIdData = BitConverter.GetBytes(unchecked((short)boardId)); // 检查是否需要交换字节 if (BitConverter.IsLittleEndian) { // 如果是小端序系统,则交换字节 byte temp = boardIdData[0]; boardIdData[0] = boardIdData[1]; boardIdData[1] = temp; } Buffer.BlockCopy(Prefix, 0, message, 0, Prefix.Length); Buffer.BlockCopy(boardIdData, 0, message, Prefix.Length, boardIdData.Length); Buffer.BlockCopy(data, 0, message, Prefix.Length + boardIdData.Length, data.Length); return message; } public List GenerateMessageList(int boardId, byte[] data, string message) { var list = new List(); ////去除不满足ASCII的数据 //message = Regex.Replace(message, @"[^\u0000-\u007F]+", string.Empty); ////总共发的数据位数 //data[1] = Convert.ToByte(message.Length); ////数据发送总帧数 //var messageCount = Math.Ceiling((decimal)message.Length / 6); //for (int i = 0; i < messageCount; i++) //{ // var tempmessage = string.Empty; // //不是最后一条指令 // if (i != messageCount - 1) // { // tempmessage = message.Substring(i * 6, 6); // var charArray = tempmessage.ToCharArray(); // for (int index = 0; index < 6; index++) // { // data[2 + index] = Convert.ToByte(charArray[index]); // } // } // //最后一条指令 // else // { // tempmessage = message.Substring(i * 6, message.Length % 6 == 0 ? 6 : message.Length % 6); // var charArray = tempmessage.ToCharArray(); // //先把所有数据位置为0 // for (int index = 0; index < 6; index++) // { // data[2 + index] = 0x00; // } // //有数据的置为对应的数据 // for (int index = 0; index < charArray.Length; index++) // { // data[2 + index] = Convert.ToByte(charArray[index]); // } // } // list.Add(GenerateMessage(boardId, data)); //} //var dataBtyes = Encoding.GetEncoding(936).GetBytes(message); var dataBtyes = Encode.Encode.GetGb2312(message); data[1] = Convert.ToByte(dataBtyes.Length); var messageCount = Math.Ceiling((decimal)dataBtyes.Length / 6); for (int i = 0; i < messageCount; i++) { byte[] charArray = dataBtyes.Skip(i * 6).Take(6).ToArray(); //不是最后一条指令 if (i != messageCount - 1) { for (int index = 0; index < 6; index++) { data[2 + index] = charArray[index]; } } //最后一条指令 else { //先把所有数据位置为0 for (int index = 0; index < 6; index++) { data[2 + index] = 0x00; } //有数据的置为对应的数据 for (int index = 0; index < charArray.Length; index++) { data[2 + index] = charArray[index]; } } list.Add(GenerateMessage(boardId, data)); } return list; } private string CharToAscii(char chr) { return ((int)chr).ToString("X").PadLeft(2, '0'); } private byte[] StrToToHexByte(string hexString) { hexString = hexString.Replace(" ", string.Empty); if ((hexString.Length % 2) != 0) hexString = "0" + hexString; byte[] returnBytes = new byte[hexString.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); return returnBytes; } } }