133 lines
4.8 KiB
C#
133 lines
4.8 KiB
C#
//------------------------------------------------------------------------------
|
||
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
|
||
// 此代码版权(除特别声明外的代码)归作者本人Diego所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议
|
||
// Gitee源代码仓库:https://gitee.com/diego2098/ThingsGateway
|
||
// Github源代码仓库:https://github.com/kimdiego2098/ThingsGateway
|
||
// 使用文档:https://thingsgateway.cn/
|
||
// QQ群:605534569
|
||
//------------------------------------------------------------------------------
|
||
|
||
using PooledAwait;
|
||
|
||
using System.Text;
|
||
|
||
using ThingsGateway.Foundation.Extension.String;
|
||
|
||
namespace ThingsGateway.Foundation;
|
||
|
||
/// <inheritdoc/>
|
||
[PluginOption(Singleton = true)]
|
||
public class DtuPlugin : PluginBase, ITcpReceivingPlugin
|
||
{
|
||
/// <summary>
|
||
/// 心跳字符串
|
||
/// </summary>
|
||
public string Heartbeat
|
||
{
|
||
get
|
||
{
|
||
return _heartbeat;
|
||
}
|
||
set
|
||
{
|
||
_heartbeat = value;
|
||
if (!heartbeatHex)
|
||
HeartbeatByte = (Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
|
||
else
|
||
HeartbeatByte = (_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
|
||
}
|
||
}
|
||
private string _heartbeat;
|
||
private Memory<byte> HeartbeatByte = new();
|
||
|
||
|
||
private bool heartbeatHex;
|
||
public bool HeartbeatHex
|
||
{
|
||
get
|
||
{
|
||
return heartbeatHex;
|
||
}
|
||
set
|
||
{
|
||
heartbeatHex = value;
|
||
if (!heartbeatHex)
|
||
HeartbeatByte = (Encoding.UTF8.GetBytes(_heartbeat ?? string.Empty));
|
||
else
|
||
HeartbeatByte = (_heartbeat?.HexStringToBytes() ?? Array.Empty<byte>());
|
||
}
|
||
}
|
||
public bool DtuIdHex { get; set; }
|
||
|
||
/// <inheritdoc/>
|
||
public Task OnTcpReceiving(ITcpSession client, BytesReaderEventArgs e)
|
||
{
|
||
return OnTcpReceiving(this, client, e);
|
||
|
||
|
||
static async PooledTask OnTcpReceiving(DtuPlugin @this, ITcpSession client, BytesReaderEventArgs e)
|
||
{
|
||
var len = @this.HeartbeatByte.Length;
|
||
if (client is TcpSessionClientChannel socket && socket.Service is ITcpServiceChannel tcpServiceChannel)
|
||
{
|
||
if (!socket.Id.StartsWith("ID="))
|
||
{
|
||
var id = @this.DtuIdHex ? $"ID={e.Reader.ToHexString()}" : $"ID={e.Reader.TotalSequence.ToString(Encoding.UTF8)}";
|
||
if (tcpServiceChannel.TryGetClient(id, out var oldClient))
|
||
{
|
||
try
|
||
{
|
||
await oldClient.CloseAsync().ConfigureAwait(false);
|
||
oldClient.Dispose();
|
||
}
|
||
catch
|
||
{
|
||
}
|
||
}
|
||
await socket.ResetIdAsync(id, client.ClosedToken).ConfigureAwait(false);
|
||
client.Logger?.Info(string.Format(AppResource.DtuConnected, id));
|
||
e.Reader.Advance((int)e.Reader.BytesRemaining);
|
||
e.Handled = true;
|
||
}
|
||
|
||
if (!socket.Service.ClientExists(socket.Id))
|
||
{
|
||
try
|
||
{
|
||
await socket.CloseAsync().ConfigureAwait(false);
|
||
socket.Dispose();
|
||
}
|
||
catch
|
||
{
|
||
}
|
||
|
||
await e.InvokeNext().ConfigureAwait(false);//如果本插件无法处理当前数据,请将数据转至下一个插件。
|
||
return;
|
||
}
|
||
|
||
if (len > 0)
|
||
{
|
||
if (@this.HeartbeatByte.Span.SequenceEqual(e.Reader.TotalSequence.Slice(0, (int)Math.Min(len, e.Reader.BytesRemaining + e.Reader.BytesRead)).First.Span))
|
||
{
|
||
if (DateTimeOffset.Now - socket.LastSentTime < TimeSpan.FromMilliseconds(200))
|
||
{
|
||
await Task.Delay(200, client.ClosedToken).ConfigureAwait(false);
|
||
}
|
||
//回应心跳包
|
||
await socket.SendAsync(@this.HeartbeatByte, socket.ClosedToken).ConfigureAwait(false);
|
||
e.Reader.Advance((int)Math.Min(len, e.Reader.BytesRemaining));
|
||
e.Handled = true;
|
||
if (socket.Logger?.LogLevel <= LogLevel.Trace)
|
||
socket.Logger?.Trace($"{socket}- Heartbeat");
|
||
}
|
||
}
|
||
}
|
||
await e.InvokeNext().ConfigureAwait(false);//如果本插件无法处理当前数据,请将数据转至下一个插件。
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
}
|