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