You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
723 lines
24 KiB
723 lines
24 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Net.Sockets;
|
||
|
|
using System.Threading;
|
||
|
|
using TouchSocket.Core;
|
||
|
|
using TouchSocket.Resources;
|
||
|
|
|
||
|
|
namespace TouchSocket.Sockets
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// TCP泛型服务器,由客户自己指定<see cref="SocketClient"/>类型。
|
||
|
|
/// </summary>
|
||
|
|
public class TcpService<TClient> : TcpServiceBase, ITcpService<TClient> where TClient : SocketClient
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 构造函数
|
||
|
|
/// </summary>
|
||
|
|
public TcpService()
|
||
|
|
{
|
||
|
|
m_socketClients = new SocketClientCollection();
|
||
|
|
m_getDefaultNewID = () =>
|
||
|
|
{
|
||
|
|
return Interlocked.Increment(ref m_nextId).ToString();
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
#region 变量
|
||
|
|
|
||
|
|
private readonly SocketClientCollection m_socketClients;
|
||
|
|
private int m_backlog;
|
||
|
|
private TouchSocketConfig m_config;
|
||
|
|
private Func<string> m_getDefaultNewID;
|
||
|
|
private int m_maxCount;
|
||
|
|
private NetworkMonitor[] m_monitors;
|
||
|
|
private long m_nextId;
|
||
|
|
private ReceiveType m_receiveType;
|
||
|
|
private ServerState m_serverState;
|
||
|
|
private bool m_usePlugin;
|
||
|
|
private bool m_useSsl;
|
||
|
|
|
||
|
|
#endregion 变量
|
||
|
|
|
||
|
|
#region 属性
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取服务器配置
|
||
|
|
/// </summary>
|
||
|
|
public override TouchSocketConfig Config => m_config;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override IContainer Container => Config?.Container;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override Func<string> GetDefaultNewID => m_getDefaultNewID;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override int MaxCount => m_maxCount;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override NetworkMonitor[] Monitors => m_monitors;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override IPluginsManager PluginsManager => Config?.PluginsManager;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override string ServerName => Config?.GetValue<string>(TouchSocketConfigExtension.ServerNameProperty);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override ServerState ServerState => m_serverState;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override SocketClientCollection SocketClients => m_socketClients;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override bool UsePlugin => m_usePlugin;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override bool UseSsl => m_useSsl;
|
||
|
|
|
||
|
|
#endregion 属性
|
||
|
|
|
||
|
|
#region 事件
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 用户连接完成
|
||
|
|
/// </summary>
|
||
|
|
public TouchSocketEventHandler<TClient> Connected { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 有用户连接的时候
|
||
|
|
/// </summary>
|
||
|
|
public OperationEventHandler<TClient> Connecting { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 有用户断开连接
|
||
|
|
/// </summary>
|
||
|
|
public DisconnectEventHandler<TClient> Disconnected { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 即将断开连接(仅主动断开时有效)。
|
||
|
|
/// <para>
|
||
|
|
/// 当主动调用Close断开时,可通过<see cref="TouchSocketEventArgs.IsPermitOperation"/>终止断开行为。
|
||
|
|
/// </para>
|
||
|
|
/// </summary>
|
||
|
|
public DisconnectEventHandler<TClient> Disconnecting { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当客户端ID被修改时触发。
|
||
|
|
/// </summary>
|
||
|
|
public IDChangedEventHandler<TClient> IDChanged { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected override sealed void OnClientConnected(ISocketClient socketClient, TouchSocketEventArgs e)
|
||
|
|
{
|
||
|
|
OnConnected((TClient)socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected override sealed void OnClientConnecting(ISocketClient socketClient, OperationEventArgs e)
|
||
|
|
{
|
||
|
|
OnConnecting((TClient)socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected override sealed void OnClientDisconnected(ISocketClient socketClient, DisconnectEventArgs e)
|
||
|
|
{
|
||
|
|
OnDisconnected((TClient)socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected override sealed void OnClientDisconnecting(ISocketClient socketClient, DisconnectEventArgs e)
|
||
|
|
{
|
||
|
|
OnDisconnecting((TClient)socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="byteBlock"></param>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
protected override sealed void OnClientReceivedData(ISocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
OnReceived((TClient)socketClient, byteBlock, requestInfo);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 客户端连接完成,覆盖父类方法将不会触发事件。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected virtual void OnConnected(TClient socketClient, TouchSocketEventArgs e)
|
||
|
|
{
|
||
|
|
Connected?.Invoke(socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 客户端请求连接,覆盖父类方法将不会触发事件。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected virtual void OnConnecting(TClient socketClient, OperationEventArgs e)
|
||
|
|
{
|
||
|
|
Connecting?.Invoke(socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 客户端断开连接,覆盖父类方法将不会触发事件。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected virtual void OnDisconnected(TClient socketClient, DisconnectEventArgs e)
|
||
|
|
{
|
||
|
|
Disconnected?.Invoke(socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 即将断开连接(仅主动断开时有效)。
|
||
|
|
/// <para>
|
||
|
|
/// 当主动调用Close断开时,可通过<see cref="TouchSocketEventArgs.IsPermitOperation"/>终止断开行为。
|
||
|
|
/// </para>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="e"></param>
|
||
|
|
protected virtual void OnDisconnecting(TClient socketClient, DisconnectEventArgs e)
|
||
|
|
{
|
||
|
|
Disconnecting?.Invoke(socketClient, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当收到适配器数据。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="byteBlock"></param>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
protected virtual void OnReceived(TClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 事件
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override void Clear()
|
||
|
|
{
|
||
|
|
string[] ids = GetIDs();
|
||
|
|
foreach (var item in ids)
|
||
|
|
{
|
||
|
|
if (TryGetSocketClient(item, out TClient client))
|
||
|
|
{
|
||
|
|
client.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取当前在线的所有客户端
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public TClient[] GetClients()
|
||
|
|
{
|
||
|
|
var clients = m_socketClients.GetClients().ToArray();
|
||
|
|
|
||
|
|
TClient[] clients1 = new TClient[clients.Length];
|
||
|
|
for (int i = 0; i < clients.Length; i++)
|
||
|
|
{
|
||
|
|
clients1[i] = (TClient)clients[i];
|
||
|
|
}
|
||
|
|
return clients1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="oldID"></param>
|
||
|
|
/// <param name="newID"></param>
|
||
|
|
/// <exception cref="ClientNotFindException"></exception>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
public override void ResetID(string oldID, string newID)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(oldID))
|
||
|
|
{
|
||
|
|
throw new ArgumentException($"“{nameof(oldID)}”不能为 null 或空。", nameof(oldID));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (string.IsNullOrEmpty(newID))
|
||
|
|
{
|
||
|
|
throw new ArgumentException($"“{nameof(newID)}”不能为 null 或空。", nameof(newID));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (oldID == newID)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (m_socketClients.TryGetSocketClient(oldID, out TClient socketClient))
|
||
|
|
{
|
||
|
|
socketClient.ResetID(newID);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new ClientNotFindException(TouchSocketStatus.ClientNotFind.GetDescription(oldID));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="config"></param>
|
||
|
|
public override IService Setup(TouchSocketConfig config)
|
||
|
|
{
|
||
|
|
m_config = config;
|
||
|
|
if (config.IsUsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IConfigPlugin>(nameof(IConfigPlugin.OnLoadingConfig), this, new ConfigEventArgs(config));
|
||
|
|
}
|
||
|
|
LoadConfig(m_config);
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IConfigPlugin>(nameof(IConfigPlugin.OnLoadedConfig), this, new ConfigEventArgs(config));
|
||
|
|
}
|
||
|
|
Container.RegisterTransient<TClient>();
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="port"></param>
|
||
|
|
public override IService Setup(int port)
|
||
|
|
{
|
||
|
|
TouchSocketConfig serviceConfig = new TouchSocketConfig();
|
||
|
|
serviceConfig.SetListenIPHosts(new IPHost[] { new IPHost(port) });
|
||
|
|
return Setup(serviceConfig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
///<inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="id"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public override bool SocketClientExist(string id)
|
||
|
|
{
|
||
|
|
return SocketClients.SocketClientExist(id);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
/// <exception cref="ArgumentNullException"></exception>
|
||
|
|
/// <exception cref="System.Exception"></exception>
|
||
|
|
public override IService Start()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
IPHost[] iPHosts = Config.GetValue(TouchSocketConfigExtension.ListenIPHostsProperty);
|
||
|
|
if (iPHosts == null || iPHosts.Length == 0)
|
||
|
|
{
|
||
|
|
throw new Exception("IPHosts为空,无法绑定");
|
||
|
|
}
|
||
|
|
switch (m_serverState)
|
||
|
|
{
|
||
|
|
case ServerState.None:
|
||
|
|
{
|
||
|
|
BeginListen(iPHosts);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case ServerState.Running:
|
||
|
|
{
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
case ServerState.Stopped:
|
||
|
|
{
|
||
|
|
BeginListen(iPHosts);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case ServerState.Disposed:
|
||
|
|
{
|
||
|
|
throw new Exception("无法重新利用已释放对象");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
m_serverState = ServerState.Running;
|
||
|
|
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||
|
|
}
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
m_serverState = ServerState.Exception;
|
||
|
|
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, ex) { Message=ex.Message });
|
||
|
|
}
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override IService Stop()
|
||
|
|
{
|
||
|
|
if (m_monitors != null)
|
||
|
|
{
|
||
|
|
foreach (var item in m_monitors)
|
||
|
|
{
|
||
|
|
item.Socket?.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
m_monitors = null;
|
||
|
|
|
||
|
|
Clear();
|
||
|
|
|
||
|
|
m_serverState = ServerState.Stopped;
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||
|
|
}
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 尝试获取TClient
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="id">ID</param>
|
||
|
|
/// <param name="socketClient">TClient</param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool TryGetSocketClient(string id, out TClient socketClient)
|
||
|
|
{
|
||
|
|
return m_socketClients.TryGetSocketClient(id, out socketClient);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="disposing"></param>
|
||
|
|
protected override void Dispose(bool disposing)
|
||
|
|
{
|
||
|
|
if (!DisposedValue)
|
||
|
|
{
|
||
|
|
if (disposing)
|
||
|
|
{
|
||
|
|
if (m_monitors != null)
|
||
|
|
{
|
||
|
|
foreach (var item in m_monitors)
|
||
|
|
{
|
||
|
|
item.Socket?.Dispose();
|
||
|
|
}
|
||
|
|
m_monitors = null;
|
||
|
|
}
|
||
|
|
Clear();
|
||
|
|
m_serverState = ServerState.Disposed;
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||
|
|
}
|
||
|
|
PluginsManager.Clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
base.Dispose(disposing);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 初始化客户端实例,默认实现为<see cref="Container.Resolve(Type, object[], string)"/>
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
protected virtual TClient GetClientInstence()
|
||
|
|
{
|
||
|
|
return Container.Resolve<TClient>();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 加载配置
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="config"></param>
|
||
|
|
protected virtual void LoadConfig(TouchSocketConfig config)
|
||
|
|
{
|
||
|
|
if (config == null)
|
||
|
|
{
|
||
|
|
throw new Exception("配置文件为空");
|
||
|
|
}
|
||
|
|
if (config.GetValue(TouchSocketConfigExtension.GetDefaultNewIDProperty) is Func<string> fun)
|
||
|
|
{
|
||
|
|
m_getDefaultNewID = fun;
|
||
|
|
}
|
||
|
|
m_usePlugin = config.IsUsePlugin;
|
||
|
|
m_maxCount = config.GetValue(TouchSocketConfigExtension.MaxCountProperty);
|
||
|
|
m_backlog = config.GetValue(TouchSocketConfigExtension.BacklogProperty);
|
||
|
|
BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty);
|
||
|
|
m_receiveType = config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty);
|
||
|
|
|
||
|
|
Logger ??= Container.Resolve<ILog>();
|
||
|
|
if (config.GetValue(TouchSocketConfigExtension.SslOptionProperty) != null)
|
||
|
|
{
|
||
|
|
m_useSsl = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 在验证Ssl发送错误时。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="ex"></param>
|
||
|
|
protected virtual void OnAuthenticatingError(System.Exception ex)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 在Socket初始化对象后,Bind之前调用。
|
||
|
|
/// 可用于设置Socket参数。
|
||
|
|
/// 父类方法可覆盖。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socket"></param>
|
||
|
|
protected virtual void PreviewBind(Socket socket)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Args_Completed(object sender, SocketAsyncEventArgs e)
|
||
|
|
{
|
||
|
|
if (e.LastOperation == SocketAsyncOperation.Accept)
|
||
|
|
{
|
||
|
|
OnAccepted(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void BeginListen(IPHost[] iPHosts)
|
||
|
|
{
|
||
|
|
int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty);
|
||
|
|
if (threadCount > 0)
|
||
|
|
{
|
||
|
|
while (!ThreadPool.SetMinThreads(threadCount, threadCount))
|
||
|
|
{
|
||
|
|
if (--threadCount <= 10)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
List<NetworkMonitor> networkMonitors = new List<NetworkMonitor>();
|
||
|
|
foreach (var iPHost in iPHosts)
|
||
|
|
{
|
||
|
|
Socket socket = new Socket(iPHost.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
|
||
|
|
{
|
||
|
|
ReceiveBufferSize = BufferLength,
|
||
|
|
SendBufferSize = BufferLength
|
||
|
|
};
|
||
|
|
if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty))
|
||
|
|
{
|
||
|
|
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||
|
|
}
|
||
|
|
PreviewBind(socket);
|
||
|
|
socket.Bind(iPHost.EndPoint);
|
||
|
|
socket.Listen(m_backlog);
|
||
|
|
|
||
|
|
networkMonitors.Add(new NetworkMonitor(iPHost, socket));
|
||
|
|
}
|
||
|
|
|
||
|
|
m_monitors = networkMonitors.ToArray();
|
||
|
|
foreach (var networkMonitor in m_monitors)
|
||
|
|
{
|
||
|
|
SocketAsyncEventArgs e = new SocketAsyncEventArgs
|
||
|
|
{
|
||
|
|
UserToken = networkMonitor.Socket
|
||
|
|
};
|
||
|
|
e.Completed += Args_Completed;
|
||
|
|
if (!networkMonitor.Socket.AcceptAsync(e))
|
||
|
|
{
|
||
|
|
OnAccepted(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnAccepted(SocketAsyncEventArgs e)
|
||
|
|
{
|
||
|
|
if (!DisposedValue)
|
||
|
|
{
|
||
|
|
if (e.SocketError == SocketError.Success && e.AcceptSocket != null)
|
||
|
|
{
|
||
|
|
Socket socket = e.AcceptSocket;
|
||
|
|
socket.ReceiveBufferSize = BufferLength;
|
||
|
|
socket.SendBufferSize = BufferLength;
|
||
|
|
if (SocketClients.Count < m_maxCount)
|
||
|
|
{
|
||
|
|
SocketInit(socket);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
socket.SafeDispose();
|
||
|
|
Logger.Warning(this, "连接客户端数量已达到设定最大值");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
e.AcceptSocket = null;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (!((Socket)e.UserToken).AcceptAsync(e))
|
||
|
|
{
|
||
|
|
OnAccepted(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
e.Dispose();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetClientConfiguration(SocketClient client)
|
||
|
|
{
|
||
|
|
client.m_usePlugin = m_usePlugin;
|
||
|
|
client.Config = m_config;
|
||
|
|
client.m_service = this;
|
||
|
|
client.Logger = Container.Resolve<ILog>();
|
||
|
|
client.m_receiveType = m_receiveType;
|
||
|
|
client.BufferLength = BufferLength;
|
||
|
|
if (client.CanSetDataHandlingAdapter)
|
||
|
|
{
|
||
|
|
client.SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.DataHandlingAdapterProperty).Invoke());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SocketInit(Socket socket)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (Config.GetValue(TouchSocketConfigExtension.NoDelayProperty))
|
||
|
|
{
|
||
|
|
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
||
|
|
}
|
||
|
|
TClient client = GetClientInstence();
|
||
|
|
SetClientConfiguration(client);
|
||
|
|
client.SetSocket(socket);
|
||
|
|
client.InternalInitialized();
|
||
|
|
|
||
|
|
OperationEventArgs args = new OperationEventArgs
|
||
|
|
{
|
||
|
|
ID = GetDefaultNewID()
|
||
|
|
};
|
||
|
|
client.InternalConnecting(args);//Connecting
|
||
|
|
if (args.IsPermitOperation)
|
||
|
|
{
|
||
|
|
client.m_id = args.ID;
|
||
|
|
if (SocketClients.TryAdd(client))
|
||
|
|
{
|
||
|
|
client.InternalConnected(new MsgEventArgs("客户端成功连接"));
|
||
|
|
if (!client.MainSocket.Connected)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (m_useSsl)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
client.BeginReceiveSsl(m_receiveType, (ServiceSslOption)m_config.GetValue(TouchSocketConfigExtension.SslOptionProperty));
|
||
|
|
}
|
||
|
|
catch (System.Exception ex)
|
||
|
|
{
|
||
|
|
OnAuthenticatingError(ex);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
client.BeginReceive(m_receiveType);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new Exception($"ID={client.m_id}重复");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
socket.SafeDispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
socket.SafeDispose();
|
||
|
|
Logger.Log(LogType.Error, this, "接收新连接错误", ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// TCP服务器
|
||
|
|
/// </summary>
|
||
|
|
public class TcpService : TcpService<SocketClient>
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 处理数据
|
||
|
|
/// </summary>
|
||
|
|
public ReceivedEventHandler<SocketClient> Received { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socketClient"></param>
|
||
|
|
/// <param name="byteBlock"></param>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
protected override void OnReceived(SocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
Received?.Invoke(socketClient, byteBlock, requestInfo);
|
||
|
|
base.OnReceived(socketClient, byteBlock, requestInfo);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|