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.
885 lines
30 KiB
885 lines
30 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.Net;
|
||
|
|
using System.Net.Sockets;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using TouchSocket.Core;
|
||
|
|
using TouchSocket.Resources;
|
||
|
|
|
||
|
|
namespace TouchSocket.Sockets
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 简单UDP会话。
|
||
|
|
/// </summary>
|
||
|
|
public class UdpSession : UdpSessionBase
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 当收到数据时
|
||
|
|
/// </summary>
|
||
|
|
public UdpReceivedEventHandler Received { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="remoteEndPoint"></param>
|
||
|
|
/// <param name="byteBlock"></param>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
protected override void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
Received?.Invoke(remoteEndPoint, byteBlock, requestInfo);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// UDP基类服务器。
|
||
|
|
/// </summary>
|
||
|
|
public class UdpSessionBase : BaseSocket, IUdpSession, IPluginObject
|
||
|
|
{
|
||
|
|
private readonly ConcurrentList<SocketAsyncEventArgs> m_socketAsyncs;
|
||
|
|
private TouchSocketConfig m_config;
|
||
|
|
private UdpDataHandlingAdapter m_adapter;
|
||
|
|
private NetworkMonitor m_monitor;
|
||
|
|
private IPHost m_remoteIPHost;
|
||
|
|
private ServerState m_serverState;
|
||
|
|
private bool m_usePlugin;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 构造函数
|
||
|
|
/// </summary>
|
||
|
|
public UdpSessionBase()
|
||
|
|
{
|
||
|
|
m_socketAsyncs = new ConcurrentList<SocketAsyncEventArgs>();
|
||
|
|
Protocol = Protocol.UDP;
|
||
|
|
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||
|
|
socket.ReceiveBufferSize = BufferLength;
|
||
|
|
socket.SendBufferSize = BufferLength;
|
||
|
|
m_monitor = new NetworkMonitor(null, socket);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 处理未经过适配器的数据。返回值表示是否继续向下传递。
|
||
|
|
/// </summary>
|
||
|
|
public Func<ByteBlock, bool> OnHandleRawBuffer { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 处理经过适配器后的数据。返回值表示是否继续向下传递。
|
||
|
|
/// </summary>
|
||
|
|
public Func<ByteBlock, IRequestInfo, bool> OnHandleReceivedData { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public bool CanSend => m_serverState == ServerState.Running;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public virtual bool CanSetDataHandlingAdapter => true;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取配置
|
||
|
|
/// </summary>
|
||
|
|
public TouchSocketConfig Config => m_config;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public IContainer Container => m_config?.Container;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public DateTime LastReceivedTime { get; private set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public DateTime LastSendTime { get; private set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 数据处理适配器
|
||
|
|
/// </summary>
|
||
|
|
public UdpDataHandlingAdapter DataHandlingAdapter => m_adapter;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 监听器
|
||
|
|
/// </summary>
|
||
|
|
public NetworkMonitor Monitor => m_monitor;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public IPluginsManager PluginsManager => m_config?.PluginsManager;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public virtual Protocol Protocol { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 默认远程节点
|
||
|
|
/// </summary>
|
||
|
|
public IPHost RemoteIPHost => m_remoteIPHost;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 服务器名称
|
||
|
|
/// </summary>
|
||
|
|
public string ServerName => Config?.GetValue(TouchSocketConfigExtension.ServerNameProperty);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取服务器状态
|
||
|
|
/// </summary>
|
||
|
|
public ServerState ServerState => m_serverState;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否已启用插件
|
||
|
|
/// </summary>
|
||
|
|
public bool UsePlugin => m_usePlugin;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 退出组播
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="multicastAddr"></param>
|
||
|
|
public void DropMulticastGroup(IPAddress multicastAddr)
|
||
|
|
{
|
||
|
|
if (DisposedValue)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException(GetType().FullName);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (multicastAddr is null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(multicastAddr));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_monitor.Socket.AddressFamily == AddressFamily.InterNetwork)
|
||
|
|
{
|
||
|
|
MulticastOption optionValue = new MulticastOption(multicastAddr);
|
||
|
|
m_monitor.Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DropMembership, optionValue);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
IPv6MulticastOption optionValue2 = new IPv6MulticastOption(multicastAddr);
|
||
|
|
m_monitor.Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.DropMembership, optionValue2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 加入组播。
|
||
|
|
/// <para>组播地址为 224.0.0.0 ~ 239.255.255.255,其中 224.0.0.0~224.255.255.255 不建议在用户程序中使用,因为它们一般都有特殊用途。</para>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="multicastAddr"></param>
|
||
|
|
public void JoinMulticastGroup(IPAddress multicastAddr)
|
||
|
|
{
|
||
|
|
if (multicastAddr is null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(multicastAddr));
|
||
|
|
}
|
||
|
|
if (DisposedValue)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException(GetType().FullName);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_monitor.Socket.AddressFamily == AddressFamily.InterNetwork)
|
||
|
|
{
|
||
|
|
MulticastOption optionValue = new MulticastOption(multicastAddr);
|
||
|
|
m_monitor.Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, optionValue);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
IPv6MulticastOption optionValue2 = new IPv6MulticastOption(multicastAddr);
|
||
|
|
m_monitor.Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, optionValue2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置数据处理适配器
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="adapter"></param>
|
||
|
|
public virtual void SetDataHandlingAdapter(UdpDataHandlingAdapter adapter)
|
||
|
|
{
|
||
|
|
if (!CanSetDataHandlingAdapter)
|
||
|
|
{
|
||
|
|
throw new Exception($"不允许自由调用{nameof(SetDataHandlingAdapter)}进行赋值。");
|
||
|
|
}
|
||
|
|
|
||
|
|
SetAdapter(adapter);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="config"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public 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));
|
||
|
|
}
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 通过端口配置
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="port"></param>
|
||
|
|
public IService Setup(int port)
|
||
|
|
{
|
||
|
|
TouchSocketConfig serverConfig = new TouchSocketConfig();
|
||
|
|
serverConfig.SetBindIPHost(new IPHost(port));
|
||
|
|
return Setup(serverConfig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 启动服务
|
||
|
|
/// </summary>
|
||
|
|
public IService Start()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (m_serverState == ServerState.Disposed)
|
||
|
|
{
|
||
|
|
throw new Exception("无法重新利用已释放对象");
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (m_serverState)
|
||
|
|
{
|
||
|
|
case ServerState.None:
|
||
|
|
{
|
||
|
|
if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) is IPHost iPHost)
|
||
|
|
{
|
||
|
|
BeginReceive(iPHost);
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case ServerState.Running:
|
||
|
|
return this;
|
||
|
|
|
||
|
|
case ServerState.Stopped:
|
||
|
|
{
|
||
|
|
if (m_config.GetValue(TouchSocketConfigExtension.BindIPHostProperty) is IPHost iPHost)
|
||
|
|
{
|
||
|
|
BeginReceive(iPHost);
|
||
|
|
}
|
||
|
|
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>
|
||
|
|
/// 停止服务器
|
||
|
|
/// </summary>
|
||
|
|
public IService Stop()
|
||
|
|
{
|
||
|
|
m_monitor?.Socket.Dispose();
|
||
|
|
m_monitor = null;
|
||
|
|
m_serverState = ServerState.Stopped;
|
||
|
|
foreach (var item in m_socketAsyncs)
|
||
|
|
{
|
||
|
|
item.SafeDispose();
|
||
|
|
}
|
||
|
|
m_socketAsyncs.Clear();
|
||
|
|
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||
|
|
}
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="disposing"></param>
|
||
|
|
protected override void Dispose(bool disposing)
|
||
|
|
{
|
||
|
|
if (!this.DisposedValue)
|
||
|
|
{
|
||
|
|
if (disposing)
|
||
|
|
{
|
||
|
|
m_monitor?.Socket.Dispose();
|
||
|
|
m_monitor = null;
|
||
|
|
m_serverState = ServerState.Disposed;
|
||
|
|
foreach (var item in m_socketAsyncs)
|
||
|
|
{
|
||
|
|
item.SafeDispose();
|
||
|
|
}
|
||
|
|
m_socketAsyncs.Clear();
|
||
|
|
|
||
|
|
if (UsePlugin)
|
||
|
|
{
|
||
|
|
PluginsManager.Raise<IServicePlugin>(nameof(IServicePlugin.OnStarted), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
base.Dispose(disposing);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 处理已接收到的数据。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="remoteEndPoint"></param>
|
||
|
|
/// <param name="byteBlock">以二进制流形式传递</param>
|
||
|
|
/// <param name="requestInfo">以解析的数据对象传递</param>
|
||
|
|
protected virtual void HandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当即将发送时,如果覆盖父类方法,则不会触发插件。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="buffer">数据缓存区</param>
|
||
|
|
/// <param name="offset">偏移</param>
|
||
|
|
/// <param name="length">长度</param>
|
||
|
|
/// <returns>返回值表示是否允许发送</returns>
|
||
|
|
protected virtual bool HandleSendingData(EndPoint endPoint, byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 加载配置
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="config"></param>
|
||
|
|
protected virtual void LoadConfig(TouchSocketConfig config)
|
||
|
|
{
|
||
|
|
if (config == null)
|
||
|
|
{
|
||
|
|
throw new Exception("配置文件为空");
|
||
|
|
}
|
||
|
|
Logger = Container.Resolve<ILog>();
|
||
|
|
m_remoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||
|
|
BufferLength = config.GetValue(TouchSocketConfigExtension.BufferLengthProperty);
|
||
|
|
m_usePlugin = config.IsUsePlugin;
|
||
|
|
|
||
|
|
if (CanSetDataHandlingAdapter)
|
||
|
|
{
|
||
|
|
SetDataHandlingAdapter(Config.GetValue(TouchSocketConfigExtension.UdpDataHandlingAdapterProperty).Invoke());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 在Socket初始化对象后,Bind之前调用。
|
||
|
|
/// 可用于设置Socket参数。
|
||
|
|
/// 父类方法可覆盖。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="socket"></param>
|
||
|
|
protected virtual void PreviewBind(Socket socket)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置适配器,该方法不会检验<see cref="CanSetDataHandlingAdapter"/>的值。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="adapter"></param>
|
||
|
|
protected void SetAdapter(UdpDataHandlingAdapter adapter)
|
||
|
|
{
|
||
|
|
if (adapter is null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(adapter));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (adapter.m_owner != null)
|
||
|
|
{
|
||
|
|
throw new Exception("此适配器已被其他终端使用,请重新创建对象。");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (Config != null)
|
||
|
|
{
|
||
|
|
if (Config.GetValue(TouchSocketConfigExtension.MaxPackageSizeProperty) is int v1)
|
||
|
|
{
|
||
|
|
adapter.MaxPackageSize = v1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
adapter.m_owner = this;
|
||
|
|
adapter.ReceivedCallBack = PrivateHandleReceivedData;
|
||
|
|
adapter.SendCallBack = DefaultSend;
|
||
|
|
m_adapter = adapter;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void BeginReceive(IPHost iPHost)
|
||
|
|
{
|
||
|
|
int threadCount = Config.GetValue(TouchSocketConfigExtension.ThreadCountProperty);
|
||
|
|
threadCount = threadCount < 0 ? 1 : threadCount;
|
||
|
|
Socket socket = new Socket(iPHost.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
|
||
|
|
{
|
||
|
|
ReceiveBufferSize = BufferLength,
|
||
|
|
SendBufferSize = BufferLength,
|
||
|
|
EnableBroadcast = m_config.GetValue(TouchSocketConfigExtension.EnableBroadcastProperty)
|
||
|
|
};
|
||
|
|
if (m_config.GetValue(TouchSocketConfigExtension.ReuseAddressProperty))
|
||
|
|
{
|
||
|
|
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
|
||
|
|
}
|
||
|
|
PreviewBind(socket);
|
||
|
|
|
||
|
|
#region Windows下UDP连接被重置错误10054
|
||
|
|
|
||
|
|
#if NET45_OR_GREATER
|
||
|
|
const int SIP_UDP_CONNRESET = -1744830452;
|
||
|
|
socket.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null);
|
||
|
|
#else
|
||
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||
|
|
{
|
||
|
|
const int SIP_UDP_CONNRESET = -1744830452;
|
||
|
|
socket.IOControl(SIP_UDP_CONNRESET, new byte[] { 0, 0, 0, 0 }, null);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
socket.Bind(iPHost.EndPoint);
|
||
|
|
|
||
|
|
m_monitor = new NetworkMonitor(iPHost, socket);
|
||
|
|
|
||
|
|
switch (m_config.GetValue(TouchSocketConfigExtension.ReceiveTypeProperty))
|
||
|
|
{
|
||
|
|
case ReceiveType.Auto:
|
||
|
|
{
|
||
|
|
#if NET45_OR_GREATER||NET5_0_OR_GREATER
|
||
|
|
for (int i = 0; i < threadCount; i++)
|
||
|
|
{
|
||
|
|
SocketAsyncEventArgs eventArg = new SocketAsyncEventArgs();
|
||
|
|
m_socketAsyncs.Add(eventArg);
|
||
|
|
eventArg.Completed += IO_Completed;
|
||
|
|
ByteBlock byteBlock = new ByteBlock(BufferLength);
|
||
|
|
eventArg.UserToken = byteBlock;
|
||
|
|
eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
|
||
|
|
eventArg.RemoteEndPoint = iPHost.EndPoint;
|
||
|
|
if (!socket.ReceiveFromAsync(eventArg))
|
||
|
|
{
|
||
|
|
ProcessReceive(socket, eventArg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||
|
|
{
|
||
|
|
for (int i = 0; i < threadCount; i++)
|
||
|
|
{
|
||
|
|
SocketAsyncEventArgs eventArg = new SocketAsyncEventArgs();
|
||
|
|
m_socketAsyncs.Add(eventArg);
|
||
|
|
eventArg.Completed += IO_Completed;
|
||
|
|
ByteBlock byteBlock = new ByteBlock(BufferLength);
|
||
|
|
eventArg.UserToken = byteBlock;
|
||
|
|
eventArg.SetBuffer(byteBlock.Buffer, 0, byteBlock.Capacity);
|
||
|
|
eventArg.RemoteEndPoint = iPHost.EndPoint;
|
||
|
|
if (!socket.ReceiveFromAsync(eventArg))
|
||
|
|
{
|
||
|
|
ProcessReceive(socket, eventArg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Thread thread = new Thread(Received);
|
||
|
|
thread.IsBackground = true;
|
||
|
|
thread.Start();
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
throw new Exception("UDP中只支持Auto模式");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Received()
|
||
|
|
{
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
ByteBlock byteBlock = new ByteBlock();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
EndPoint endPoint = m_monitor.IPHost.EndPoint;
|
||
|
|
int r = m_monitor.Socket.ReceiveFrom(byteBlock.Buffer, ref endPoint);
|
||
|
|
byteBlock.SetLength(r);
|
||
|
|
HandleBuffer(endPoint, byteBlock);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
byteBlock.Dispose();
|
||
|
|
Logger.Log(LogType.Error, this, ex.Message, ex);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void HandleBuffer(EndPoint endPoint, ByteBlock byteBlock)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
LastReceivedTime = DateTime.Now;
|
||
|
|
if (OnHandleRawBuffer?.Invoke(byteBlock) == false)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (DisposedValue)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (m_adapter == null)
|
||
|
|
{
|
||
|
|
Logger.Error(this, TouchSocketStatus.NullDataAdapter.GetDescription());
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
m_adapter.ReceivedInput(endPoint, byteBlock);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
Logger.Log(LogType.Error, this, "在处理数据时发生错误", ex);
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
byteBlock.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void IO_Completed(object sender, SocketAsyncEventArgs e)
|
||
|
|
{
|
||
|
|
ProcessReceive((Socket)sender, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void PrivateHandleReceivedData(EndPoint remoteEndPoint, ByteBlock byteBlock, IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
if (OnHandleReceivedData?.Invoke(byteBlock, requestInfo) == false)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_usePlugin)
|
||
|
|
{
|
||
|
|
UdpReceivedDataEventArgs args = new UdpReceivedDataEventArgs(remoteEndPoint, byteBlock, requestInfo);
|
||
|
|
PluginsManager.Raise<IUdpSessionPlugin>(nameof(IUdpSessionPlugin.OnReceivedData), this, args);
|
||
|
|
if (args.Handled)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
HandleReceivedData(remoteEndPoint, byteBlock, requestInfo);
|
||
|
|
}
|
||
|
|
|
||
|
|
#region 向默认远程同步发送
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 向默认终结点发送
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public virtual void Send(byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
if (m_remoteIPHost == null)
|
||
|
|
{
|
||
|
|
throw new Exception("默认终结点为空");
|
||
|
|
}
|
||
|
|
Send(m_remoteIPHost.EndPoint, buffer, offset, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
/// <exception cref="OverlengthException"></exception>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
public virtual void Send(IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
if (DisposedValue)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (m_adapter == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription());
|
||
|
|
}
|
||
|
|
if (!m_adapter.CanSendRequestInfo)
|
||
|
|
{
|
||
|
|
throw new NotSupportedException($"当前适配器不支持对象发送。");
|
||
|
|
}
|
||
|
|
m_adapter.SendInput(requestInfo);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 向默认远程同步发送
|
||
|
|
|
||
|
|
#region 向默认远程异步发送
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// IOCP发送
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <exception cref="NotConnectedException"></exception>
|
||
|
|
/// <exception cref="OverlengthException"></exception>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
public virtual Task SendAsync(byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
Send(buffer, offset, length);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
/// <exception cref="OverlengthException"></exception>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
public virtual Task SendAsync(IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
Send(requestInfo);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 向默认远程异步发送
|
||
|
|
|
||
|
|
#region 向设置的远程同步发送
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 向设置的远程同步发送
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="remoteEP"></param>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <exception cref="NotConnectedException"></exception>
|
||
|
|
/// <exception cref="OverlengthException"></exception>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
public virtual void Send(EndPoint remoteEP, byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
m_adapter.SendInput(remoteEP, buffer, offset, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 向设置的远程同步发送
|
||
|
|
|
||
|
|
#region 向设置的远程异步发送
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 向设置的远程异步发送
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="remoteEP"></param>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <exception cref="NotConnectedException"></exception>
|
||
|
|
/// <exception cref="OverlengthException"></exception>
|
||
|
|
/// <exception cref="Exception"></exception>
|
||
|
|
public virtual Task SendAsync(EndPoint remoteEP, byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
Send(remoteEP, buffer, offset, length);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 向设置的远程异步发送
|
||
|
|
|
||
|
|
private void ProcessReceive(Socket socket, SocketAsyncEventArgs e)
|
||
|
|
{
|
||
|
|
if (m_serverState == ServerState.Running && e.SocketError == SocketError.Success)
|
||
|
|
{
|
||
|
|
ByteBlock byteBlock = (ByteBlock)e.UserToken;
|
||
|
|
byteBlock.SetLength(e.BytesTransferred);
|
||
|
|
|
||
|
|
HandleBuffer(e.RemoteEndPoint, byteBlock);
|
||
|
|
|
||
|
|
ByteBlock newByteBlock = new ByteBlock(BufferLength);
|
||
|
|
e.UserToken = newByteBlock;
|
||
|
|
e.SetBuffer(newByteBlock.Buffer, 0, newByteBlock.Buffer.Length);
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (!socket.ReceiveFromAsync(e))
|
||
|
|
{
|
||
|
|
ProcessReceive(socket, e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (System.Exception ex)
|
||
|
|
{
|
||
|
|
Logger.Log(LogType.Error, this, ex.Message, ex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (e.SocketError != SocketError.Success)
|
||
|
|
{
|
||
|
|
Logger?.Error(this, $"接收出现错误:{e.SocketError},错误代码:{(int)e.SocketError}");
|
||
|
|
e.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#region DefaultSend
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public void DefaultSend(byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
DefaultSend(m_remoteIPHost.EndPoint, buffer, offset, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public void DefaultSend(EndPoint endPoint, byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
if (HandleSendingData(endPoint, buffer, offset, length))
|
||
|
|
{
|
||
|
|
if (CanSend)
|
||
|
|
{
|
||
|
|
m_monitor.Socket.SendTo(buffer, offset, length, SocketFlags.None, endPoint);
|
||
|
|
}
|
||
|
|
|
||
|
|
LastSendTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion DefaultSend
|
||
|
|
|
||
|
|
#region DefaultSendAsync
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public Task DefaultSendAsync(byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
DefaultSend(buffer, offset, length);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public Task DefaultSendAsync(EndPoint endPoint, byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
DefaultSend(buffer, offset, length);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion DefaultSendAsync
|
||
|
|
|
||
|
|
#region 组合发送
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="transferBytes"></param>
|
||
|
|
public void Send(IList<ArraySegment<byte>> transferBytes)
|
||
|
|
{
|
||
|
|
Send(m_remoteIPHost.EndPoint, transferBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="transferBytes"></param>
|
||
|
|
public void Send(EndPoint endPoint, IList<ArraySegment<byte>> transferBytes)
|
||
|
|
{
|
||
|
|
if (m_adapter == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(DataHandlingAdapter), TouchSocketStatus.NullDataAdapter.GetDescription());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!m_adapter.CanSplicingSend)
|
||
|
|
{
|
||
|
|
throw new NotSupportedException("该适配器不支持拼接发送");
|
||
|
|
}
|
||
|
|
m_adapter.SendInput(endPoint, transferBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="transferBytes"></param>
|
||
|
|
public Task SendAsync(IList<ArraySegment<byte>> transferBytes)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
Send(transferBytes);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="transferBytes"></param>
|
||
|
|
public Task SendAsync(EndPoint endPoint, IList<ArraySegment<byte>> transferBytes)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
Send(endPoint, transferBytes);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 组合发送
|
||
|
|
}
|
||
|
|
}
|