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