Files
ThingsGateway/src/Foundation/ThingsGateway.Foundation/Channel/TcpServiceChannel.cs
2025-08-28 15:35:43 +08:00

278 lines
9.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using ThingsGateway.NewLife;
namespace ThingsGateway.Foundation;
/// <summary>
/// TCP服务器
/// </summary>
/// <typeparam name="TClient"></typeparam>
public abstract class TcpServiceChannelBase<TClient> : TcpService<TClient>, ITcpService<TClient> where TClient : TcpSessionClientChannel, new()
{
/// <inheritdoc/>
public ConcurrentList<IDevice> Collects { get; } = new();
public async Task ClientDisposeAsync(string id)
{
if (this.TryGetClient(id, out var client))
{
//if (ShutDownEnable)
// await client.ShutdownAsync(System.Net.Sockets.SocketShutdown.Both).ConfigureAwait(false);
await client.CloseAsync().ConfigureAwait(false);
client.SafeDispose();
}
}
private readonly WaitLock _connectLock = new WaitLock(nameof(TcpServiceChannelBase<TClient>));
/// <inheritdoc/>
public override async Task StartAsync()
{
if (ServerState != ServerState.Running)
{
try
{
await _connectLock.WaitAsync().ConfigureAwait(false);
if (ServerState != ServerState.Running)
{
if (ServerState != ServerState.Stopped)
{
await base.StopAsync().ConfigureAwait(false);
}
//await SetupAsync(Config.Clone()).ConfigureAwait(false);
await base.StartAsync().ConfigureAwait(false);
if (ServerState == ServerState.Running)
{
Logger?.Info($"{Monitors.FirstOrDefault()?.Option.IpHost}{AppResource.ServiceStarted}");
}
}
}
finally
{
var cts = m_transport;
m_transport = new();
cts?.SafeCancel();
cts?.SafeDispose();
_connectLock.Release();
}
}
}
/// <inheritdoc/>
public override async Task<Result> StopAsync(CancellationToken token)
{
if (Monitors.Any())
{
try
{
await _connectLock.WaitAsync(token).ConfigureAwait(false);
if (Monitors.Any())
{
await ClearAsync().ConfigureAwait(false);
var iPHost = Monitors.FirstOrDefault()?.Option.IpHost;
var result = await base.StopAsync(token).ConfigureAwait(false);
if (!Monitors.Any())
Logger?.Info($"{iPHost}{AppResource.ServiceStoped}");
return result;
}
}
finally
{
var cts = m_transport;
m_transport = null;
cts?.SafeCancel();
cts?.SafeDispose();
_connectLock.Release();
}
}
else
{
var result = await base.StopAsync(token).ConfigureAwait(false);
return result;
}
return Result.Success;
}
public CancellationToken ClosedToken => this.m_transport == null ? new CancellationToken(true) : this.m_transport.Token;
private CancellationTokenSource m_transport;
protected override void SafetyDispose(bool disposing)
{
m_transport?.SafeCancel();
m_transport?.SafeDispose();
m_transport = null;
base.SafetyDispose(disposing);
}
/// <inheritdoc/>
protected override Task OnTcpClosed(TClient socketClient, ClosedEventArgs e)
{
Logger?.Info($"{socketClient} Closed{(e.Message.IsNullOrEmpty() ? string.Empty : $"-{e.Message}")}");
return base.OnTcpClosed(socketClient, e);
}
/// <inheritdoc/>
protected override Task OnTcpClosing(TClient socketClient, ClosingEventArgs e)
{
Logger?.Trace($"{socketClient} Closing{(e.Message.IsNullOrEmpty() ? string.Empty : $"-{e.Message}")}");
return base.OnTcpClosing(socketClient, e);
}
/// <inheritdoc/>
protected override Task OnTcpConnected(TClient socketClient, ConnectedEventArgs e)
{
Logger?.Info($"{socketClient} Connected");
return base.OnTcpConnected(socketClient, e);
}
/// <inheritdoc/>
protected override Task OnTcpConnecting(TClient socketClient, ConnectingEventArgs e)
{
Logger?.Trace($"{socketClient} Connecting");
return base.OnTcpConnecting(socketClient, e);
}
}
/// <summary>
/// Tcp服务器通道
/// </summary>
public class TcpServiceChannel<TClient> : TcpServiceChannelBase<TClient>, IChannel, ITcpServiceChannel where TClient : TcpSessionClientChannel, IClientChannel, IChannel, new()
{
/// <inheritdoc/>
public TcpServiceChannel(IChannelOptions channelOptions)
{
ChannelOptions = channelOptions;
}
public override TouchSocketConfig Config => base.Config ?? ChannelOptions.Config;
/// <inheritdoc/>
public ChannelReceivedEventHandler ChannelReceived { get; } = new();
/// <inheritdoc/>
public IChannelOptions ChannelOptions { get; }
/// <inheritdoc/>
public ChannelTypeEnum ChannelType => ChannelOptions.ChannelType;
/// <inheritdoc/>
public bool Online => ServerState == ServerState.Running;
/// <inheritdoc/>
public ChannelEventHandler Started { get; } = new();
/// <inheritdoc/>
public ChannelEventHandler Starting { get; } = new();
/// <inheritdoc/>
public ChannelEventHandler Stoped { get; } = new();
/// <inheritdoc/>
public ChannelEventHandler Stoping { get; } = new();
/// <inheritdoc/>
public Task<Result> CloseAsync(string msg, CancellationToken token)
{
return StopAsync(token);
}
/// <inheritdoc/>
public Task ConnectAsync(CancellationToken token = default)
{
if (token.IsCancellationRequested)
return EasyTask.CompletedTask;
return StartAsync();
}
/// <inheritdoc/>
public override string? ToString()
{
return $"{ChannelOptions.BindUrl} {ChannelOptions.RemoteUrl}";
}
/// <inheritdoc/>
protected override TClient NewClient()
{
var data = new TClient();
data.ResetSign(MinSign, MaxSign);
return data;
}
public int MinSign { get; private set; } = 0;
public int MaxSign { get; private set; } = ushort.MaxValue;
public void ResetSign(int minSign = 0, int maxSign = ushort.MaxValue)
{
MinSign = minSign;
MaxSign = maxSign;
}
/// <inheritdoc/>
protected override async Task OnTcpClosing(TClient socketClient, ClosingEventArgs e)
{
await socketClient.OnChannelEvent(Stoping).ConfigureAwait(false);
await base.OnTcpClosing(socketClient, e).ConfigureAwait(false);
}
/// <inheritdoc/>
protected override async Task OnTcpClosed(TClient socketClient, ClosedEventArgs e)
{
await socketClient.OnChannelEvent(Stoped).ConfigureAwait(false);
await base.OnTcpClosed(socketClient, e).ConfigureAwait(false);
}
/// <inheritdoc/>
protected override async Task OnTcpConnected(TClient socketClient, ConnectedEventArgs e)
{
await socketClient.OnChannelEvent(Started).ConfigureAwait(false);
await base.OnTcpConnected(socketClient, e).ConfigureAwait(false);
}
/// <inheritdoc/>
protected override async Task OnTcpConnecting(TClient socketClient, ConnectingEventArgs e)
{
await socketClient.OnChannelEvent(Starting).ConfigureAwait(false);
await base.OnTcpConnecting(socketClient, e).ConfigureAwait(false);
}
/// <inheritdoc/>
protected override async Task OnTcpReceived(TClient socketClient, ReceivedDataEventArgs e)
{
var receivedTask = base.OnTcpReceived(socketClient, e);
if (!receivedTask.IsCompleted)
await receivedTask.ConfigureAwait(false);
if (e.Handled)
return;
var channelReceivedTask = socketClient.OnChannelReceivedEvent(e, ChannelReceived);
if (!channelReceivedTask.IsCompleted)
await channelReceivedTask.ConfigureAwait(false);
}
IEnumerable<TcpSessionClientChannel> ITcpServiceChannel.Clients => base.Clients;
protected override void ClientInitialized(TClient client)
{
client.ChannelOptions = ChannelOptions;
client.WaitLock = new NewLife.WaitLock(nameof(TcpServiceChannelBase<TClient>), ChannelOptions.WaitLock.MaxCount);
base.ClientInitialized(client);
}
public bool TryGetClient(string id, out TcpSessionClientChannel client)
{
bool result = ServiceExtension.TryGetClient<TClient>(this, id, out var tclient);
client = tclient;
return result;
}
}