You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
10 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Serilog;
using SlnMesnac.Common;
using SlnMesnac.Model.dto;
using SlnMesnac.Model.Enum;
using SlnMesnac.Serilog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;
#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本4.0.30319.42000
* 机器名称LAPTOP-E0N2L34V
* 命名空间SlnMesnac.TouchSocket
* 唯一标识496f8d2b-70e3-4a05-ae18-a9b0fcd06b82
*
* 创建者WenJY
* 电子邮箱wenjy@mesnac.com
* 创建时间2024-03-27 21:58:35
* 版本V1.0.0
* 描述:
*
*--------------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本V1.0.0
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
namespace SlnMesnac.TouchSocket
{
public class TcpServer
{
private SerilogHelper _logger;
private readonly TcpService _service;
/// <summary>
/// 接收客户端指令委托
/// </summary>
public delegate void ReceivedClientBuffer(byte[] buffer);
public event ReceivedClientBuffer? ReceivedClientBufferEvent;
public delegate void RefreshClientInfo(TcpService tcpService);
public event RefreshClientInfo? RefreshClientInfoEvent;
private StringChange _stringChange;
public TcpServer(SerilogHelper logger, StringChange stringChange, TcpService tcpService)
{
_logger = logger;
_service = tcpService;
_stringChange = stringChange;
}
public void Init(int serverPort)
{
try
{
_service.Connecting = (client, e) =>
{
Log.Information($"客户端{client.IP}正在接入服务");
if (!client.IsClient)
{
e.Id = $"{client.IP}:{client.Port}";
}
return EasyTask.CompletedTask;
};
_service.Connected = (client, e) =>
{
Log.Information($"客户端{client.IP}接入服务成功");
RefreshClientInfoEvent?.Invoke(_service);
return EasyTask.CompletedTask;
};
_service.Closed = (client, e) =>
{
Log.Information($"客户端{client.IP}断开连接");
RefreshClientInfoEvent?.Invoke(_service);
return EasyTask.CompletedTask;
};
_service.Received = (client, e) =>
{
//从客户端收到信息
//var mes = Encoding.UTF8.GetString(e.Memory.Span.ToArray(), 0, e.Memory.Span.Length);//注意数据长度是byteBlock.Len
byte[] receivedBuffer = new byte[e.Memory.Span.Length];
Array.Copy(e.Memory.Span.ToArray(), 0, receivedBuffer, 0, e.Memory.Span.Length);
//MES客户端消息解析
if (receivedBuffer[4] == 0x65)
{
byte[] addrby = new byte[2];
Array.Copy(receivedBuffer, 1, addrby, 0, 2);
var flag = BitConverter.ToUInt16(addrby, 0);
_service.ResetIdAsync($"{client.IP}:{client.Port}", flag.ToString());
}
//ReceivedClientBufferEvent?.Invoke(receivedBuffer);
return EasyTask.CompletedTask;
};
_service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost($"0.0.0.0:{serverPort}") })
.ConfigureContainer(a =>//容器的配置顺序应该在最前面
{
a.AddConsoleLogger();
})
.ConfigurePlugins(a =>
{
//自定义插件
}));
_service.StartAsync();
Log.Information($"TcpServer启动成功监听端口{serverPort}");
Task.Run(async delegate
{
//await Task.Delay(1000 * 20);
SendHeartBeat();
});
}
catch (Exception ex)
{
//throw new InvalidOperationException($"TcpServer启动异常{ex.Message}");
Log.Information($"TcpServer启动异常{ex.Message}");
}
}
public byte DealMessage(byte[] bytes)
{
byte XOR = 0;
try
{
byte[] datalen = new byte[bytes.Length - 8];
Array.Copy(bytes,4,datalen,0, bytes.Length - 8);
string asciiStr = Encoding.ASCII.GetString(datalen);
byte[] resultBytes = new byte[asciiStr.Length / 2];
for (int i = 0; i < asciiStr.Length / 2; i++)
{
int startIndex = i * 2;
int length = Math.Min(2, asciiStr.Length - startIndex);
string hexPair = asciiStr.Substring(startIndex, length);
resultBytes[i] = Convert.ToByte(hexPair, 16);
}
XOR = CalculateVerify(resultBytes, resultBytes.Length);
string sss = XOR.ToString("X2");
return XOR;
}
catch (Exception ex)
{
return XOR;
}
}
public byte CalculateVerify(byte[] pMessage, int iLength)
{
UInt16 i;
byte iVerify = 0;
iVerify = pMessage[0];
for (i = 1; i < iLength; i++)
{
iVerify = (byte)(iVerify ^ pMessage[i]);
}
return iVerify;
}
public struct Heart
{
public Head head;
public Tail tail;
}
public struct Head
{
public byte start; //起始
public byte[] addr; //软件地址
public byte mstaseq; //主站地址与命令序号
public byte control; //控制码
public byte[] length; //数据长度
}
public struct Tail
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] verifica; //校验码
public byte end; //结束码
}
/// <summary>
/// 向所有客户端发送心跳
/// </summary>
public void SendHeartBeat()
{
byte[] Heartbuf = new byte[10];
byte[] u16byte = new byte[2];
SoftMessagePack pMessagePackInfo = new SoftMessagePack();
pMessagePackInfo.iStationId = 1;
pMessagePackInfo.iMsta = 0XF0 + 1;
pMessagePackInfo.iLen = 0;
pMessagePackInfo.iMessageType = (byte)MessageType.HeartPack_Type;
while (true)
{
try
{
SendMessage(pMessagePackInfo);
}
catch (Exception ex)
{
Log.Information($"SendHeartBeat异常{ex.Message}");
}
Thread.Sleep(1000 * 5 * 1);
}
}
public async void SendMessage(SoftMessagePack pMessagePack)
{
UInt16 iPos = 0;
byte[] u16byte = new byte[2];
try
{
byte[] SendBuffer = new byte[pMessagePack.iLen + 10];
SendBuffer[iPos] = pMessagePack.iSys;
iPos += 1;
u16byte = BitConverter.GetBytes(pMessagePack.iStationId); //站号
//u16byte = Swap16Bytes(u16byte); //协议里为大端在前
Array.Copy(u16byte, 0, SendBuffer, iPos, 2);
iPos += 2;
SendBuffer[iPos] = pMessagePack.iMsta; //主站地址
iPos += 1;
SendBuffer[iPos] = pMessagePack.iMessageType; //帧类型
iPos += 1;
u16byte = BitConverter.GetBytes(pMessagePack.iLen); //长度
//u16byte = Swap16Bytes(u16byte); //协议里为大端在前
Array.Copy(u16byte, 0, SendBuffer, iPos, 2);
iPos += 2;
if (pMessagePack.iLen > 0)
{
Array.Copy(pMessagePack.pMessage, 0, SendBuffer, iPos, pMessagePack.iLen); //数据域
iPos += (ushort)(pMessagePack.iLen);
}
u16byte = _stringChange.CalculateVerifytobyte(SendBuffer, pMessagePack.iLen + 7); //校验码
Array.Copy(u16byte, 0, SendBuffer, iPos, 2);
iPos += 2;
SendBuffer[iPos] = pMessagePack.iEndChar; //结束符1
iPos += 1;
ReadOnlyMemory<byte> readOnlyMemory = new ReadOnlyMemory<byte>(SendBuffer);
foreach (var item in _service.Clients)
{
#region Tcp服务器按目标Id先查找再回应
if (_service.Clients.TryGetClient(item.Id, out var tcpSessionClient))
{
await tcpSessionClient.SendAsync(readOnlyMemory);
}
#endregion
Log.Information($"{pMessagePack.iStationId}发送原始报文{_stringChange.bytesToHexStr(SendBuffer, SendBuffer.Length)}");
}
}
catch (Exception ex)
{
Log.Information($"SendMessage异常{ex.Message}");
}
}
}
}