using System.Collections.Concurrent;
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
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 bool IsOnline { 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 ConcurrentDictionary MessageList { get; set; } = new ConcurrentDictionary();
public TcpClient tcpClient { get; set; }
public object receivdLockObject = new object();
public object sendLockObject = new object();
public bool Connect()
{
try
{
tcpClient.Connect();//调用连接,当连接不成功时,会抛出异常。
return true;
}
catch (Exception e)
{
//连接失败
return false;
}
}
///
/// 初始化配置连接
///
///
public TCPClient(string remoteIPHost, string bindIPHost)
{
try
{
RemoteIPHost = remoteIPHost;
BindIPHost = bindIPHost;
tcpClient = new TcpClient();
//载入配置
tcpClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost(RemoteIPHost)
.SetBindIPHost(BindIPHost)
.ConfigurePlugins(a =>
{
//配置断线重连
a.UseReconnection(-1, true, 1000);
})
.ConfigureContainer(a =>
{
//添加控制台日志注入
a.AddConsoleLogger();
}));
//添加接收事件 匹配已发送的指令
tcpClient.Received += (client, e) =>
{
var data = e.ByteBlock.Buffer.Take((int)e.ByteBlock.Length).ToArray();
e.ByteBlock.Clear();
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 = (data[PreFixLength + 0] << 8) + data[PreFixLength + 1];
//查询当前板子是否有待验证的指令
var message = new MessageDto();
MessageList.TryGetValue(boardId, out message);
//功能位校验 功能位相同视为已响应指令 删除对应的指令
if (message?.Message[PreFixLength + 2] == dataTemp[PreFixLength + 2])
{
MessageList.TryRemove(boardId, out message);
}
index += (PreFixLength + DataLength - 1);//每次循环index会+1 所以这里-1
}
}
return null;
};
tcpClient.Connected += (client, e) =>
{
this.IsOnline = true;
return EasyTask.CompletedTask;
};
tcpClient.Disconnected += (client, e) =>
{
this.IsOnline = false;
return EasyTask.CompletedTask;
};
//配置数据重发机制
Task.Run(async () =>
{
while (true)
{
try
{
//TO DO如果指令未回应n次 则取消重发
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
await Task.Delay(3000);
if (MessageList.Count > 0)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
foreach (var item in MessageList)
{
if (item.Value.LastSendTime < DateTime.Now.AddSeconds(3))
{
tcpClient.Send(item.Value.Message);
item.Value.SendTimes++;
item.Value.LastSendTime = DateTime.Now;
await Task.Delay(10);
}
}
}
}
catch
{
}
}
});
}
catch (Exception ex)
{
}
}
public void Send(byte[] message)
{
var boardId = (message[3] << 8) + message[4];
//记录发送指令 用于通信校验 同Id只校验最后一个指令
////MessageList.AddOrUpdate(boardId, new MessageDto()
////{
//// ID = boardId,
//// Message = message,
////}, (key, oldValue) => oldValue = new MessageDto()
////{
//// ID = boardId,
//// Message = message,
////});
lock (sendLockObject)
{
tcpClient.Send(message);
//发送自带10ms间隔
Thread.Sleep(10);
}
}
//生成协议明细
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 class MessageDto
{
public int ID { get; set; }
///
/// 最后一次发送时间
///
public DateTime LastSendTime { get; set; } = DateTime.Now;
///
/// 发送内容
///
public byte[] Message { get; set; }
///
/// 发送次数
///
public int SendTimes { get; set; } = 0;//第几次发送
}
}