mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 01:46:44 +08:00
发布rc1版本,新增net8版本适配版本。重构websocket
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildProjectName).snk</AssemblyOriginatorKeyFile>
|
||||
<Version>2.0.0-beta.280</Version>
|
||||
<Version>2.0.0-rc.1</Version>
|
||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2023 若汝棋茗</Copyright>
|
||||
<Copyright>Copyright © 2024 若汝棋茗</Copyright>
|
||||
<PackageProjectUrl>https://gitee.com/rrqm_home/touchsocket</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
@@ -20,6 +20,7 @@
|
||||
<BaseOutputPath>..\..\Build</BaseOutputPath>
|
||||
<DocumentationFile></DocumentationFile>
|
||||
<RepositoryUrl>https://gitee.com/rrqm_home/touchsocket</RepositoryUrl>
|
||||
<NoWarn>IDE0290;IDE0090</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
@@ -27,7 +28,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
|
||||
<DefineConstants>ValueTask;SystemNetHttp</DefineConstants>
|
||||
<DefineConstants>SystemNetHttp</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net45'">
|
||||
|
||||
@@ -53,6 +54,9 @@
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net7.0'">
|
||||
<DefineConstants>ValueTask;Unsafe;SystemNetHttp;SystemMemory;SystemTextJson</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0'">
|
||||
<DefineConstants>ValueTask;Unsafe;SystemNetHttp;SystemMemory;SystemTextJson</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE.txt">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
<PackageTags>Tcp;Udp;Ssl;Socket;Saea;AspNetCore;TouchSocket</PackageTags>
|
||||
<Description>TouchSocket.AspNetCore是适用于AspNetCore的专属版本。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>IOC;Autofac;DependencyInjection;TouchSocket</PackageTags>
|
||||
<Description>这是一个为Core中扩展Ioc容器为Autofac的库。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net461;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>IOC;DependencyInjection;TouchSocket</PackageTags>
|
||||
<Description>这是一个为Core中扩展Ioc容器为IServiceCollection的库。
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace TouchSocket.Core
|
||||
{
|
||||
@@ -39,7 +40,7 @@ namespace TouchSocket.Core
|
||||
/// <param name="pluginManager"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="func"></param>
|
||||
public static void Add<TSender, TEventArgs>(this IPluginManager pluginManager, string name, Func<TSender, TEventArgs, Task> func) where TEventArgs : PluginEventArgs
|
||||
public static void Add<TSender, TEventArgs>(this IPluginManager pluginManager, string name,Func<TSender, TEventArgs, Task> func) where TEventArgs : PluginEventArgs
|
||||
{
|
||||
Task newFunc(object sender, TouchSocketEventArgs e)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Message;ArrayPool;Logger;Plugin;3DES;Xml;FilePool;Serialize;TouchSocket</PackageTags>
|
||||
<Description>这是一个基础服务功能的库,其中包含:内存池、对象池、文件池、流式数据解包器、等待逻辑池、AppMessenger、3DES加密、Xml快速存储、运行时间测量器、文件快捷操作、高性能二进制序列化器、规范日志接口等。
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net7.0'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
|
||||
@@ -13,27 +13,14 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Dmtp
|
||||
{
|
||||
/// <summary>
|
||||
/// IWebSocketDmtpClient
|
||||
/// </summary>
|
||||
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase, ISetupConfigObject
|
||||
public interface IWebSocketDmtpClient : IWebSocketDmtpClientBase, ISetupConfigObject,IConnectObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步连接
|
||||
/// </summary>
|
||||
/// <param name="millisecondsTimeout">验证超时时间</param>
|
||||
/// <returns></returns>
|
||||
Task ConnectAsync(int millisecondsTimeout = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 异步连接
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <returns></returns>
|
||||
Task ConnectAsync(CancellationToken token, int millisecondsTimeout = 5000);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Dmtp
|
||||
/// <summary>
|
||||
/// 基于WebSocket协议的Dmtp终端接口
|
||||
/// </summary>
|
||||
public interface IWebSocketDmtpClientBase :IConfigObject, IClient, IPluginObject, IDmtpActorObject, IHandshakeObject, IResolverObject
|
||||
public interface IWebSocketDmtpClientBase :IConfigObject, IClient, IPluginObject, IDmtpActorObject, IHandshakeObject, IResolverObject,ICloseObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端的Id
|
||||
|
||||
@@ -56,55 +56,16 @@ namespace TouchSocket.Dmtp
|
||||
|
||||
#endregion 字段
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool CanSend => this.m_client.State == WebSocketState.Open;
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
/// </summary>
|
||||
public DisconnectEventHandler<WebSocketDmtpClient> Disconnected { get; set; }
|
||||
#region 连接
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDmtpActor DmtpActor { get => this.m_dmtpActor; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Id => this.m_dmtpActor?.Id;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsHandshaked { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; } = DmtpUtility.DmtpProtocol;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送<see cref="IDmtpActor"/>关闭消息。
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
public void Close(string msg = "")
|
||||
public void Connect(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
this.m_dmtpActor.SendClose(msg);
|
||||
this.m_dmtpActor.Close(msg);
|
||||
this.PrivateClose(msg);
|
||||
this.ConnectAsync(millisecondsTimeout, token).GetFalseAwaitResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task ConnectAsync(int millisecondsTimeout = 5000)
|
||||
{
|
||||
return this.ConnectAsync(CancellationToken.None, millisecondsTimeout);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task ConnectAsync(CancellationToken token, int millisecondsTimeout = 5000)
|
||||
public async Task ConnectAsync(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -151,6 +112,45 @@ namespace TouchSocket.Dmtp
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
/// </summary>
|
||||
public DisconnectEventHandler<WebSocketDmtpClient> Disconnected { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDmtpActor DmtpActor { get => this.m_dmtpActor; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Id => this.m_dmtpActor?.Id;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsHandshaked { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; } = DmtpUtility.DmtpProtocol;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送<see cref="IDmtpActor"/>关闭消息。
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
public void Close(string msg)
|
||||
{
|
||||
this.m_dmtpActor.SendClose(msg);
|
||||
this.m_dmtpActor.Close(msg);
|
||||
this.PrivateClose(msg);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Ping(string targetId, int millisecondsTimeout = 5000)
|
||||
@@ -267,7 +267,7 @@ namespace TouchSocket.Dmtp
|
||||
|
||||
private void PrivateClose(string msg)
|
||||
{
|
||||
this.BreakOut($"调用{nameof(Close)}", true);
|
||||
this.BreakOut(msg, true);
|
||||
}
|
||||
|
||||
private void PrivateHandleReceivedData(ByteBlock byteBlock, IRequestInfo requestInfo)
|
||||
@@ -415,28 +415,5 @@ namespace TouchSocket.Dmtp
|
||||
}
|
||||
|
||||
#endregion 事件触发
|
||||
|
||||
#region Receiver
|
||||
|
||||
/// <summary>
|
||||
/// 不支持该功能
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public void ClearReceiver()
|
||||
{
|
||||
throw new NotSupportedException("不支持该功能");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 不支持该功能
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public IReceiver CreateReceiver()
|
||||
{
|
||||
throw new NotSupportedException("不支持该功能");
|
||||
}
|
||||
|
||||
#endregion Receiver
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Duplex;Rpc;FileTransfer;Redis;TouchSocket</PackageTags>
|
||||
<Description>DMTP(Duplex Message Transport Protocol双工消息传输协议)是一个简单易用,便捷高效,且易于扩展的二进制数据协议。目前基于该协议,已实现的功能包括:连接验证、同步Id、Rpc(包括客户端请求服务器,服务器请求客户端、客户端请求客户端)、文件传输(包括客户端向服务器请求文件、客户端向服务器推送文件、服务器向客户端请求文件、服务器向客户端推送文件、
|
||||
客户端之间请求、推送文件)、Redis等。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net461;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Hosting;Socket;JsonRpc;NamedPipe;XmlRpc;Dmtp;TouchSocket</PackageTags>
|
||||
<Description>这是TouchSocket基于通用主机的扩展。目前包括Tcp、Udp、NamedPipe、Dmtp、SerialPort等服务。
|
||||
|
||||
@@ -21,9 +21,39 @@
|
||||
<ProjectReference Include="..\TouchSocket\TouchSocket.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net462'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net472'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.1'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net6.0'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net7.0'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)'=='net8.0'">
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -39,6 +39,13 @@ namespace TouchSocket.Http
|
||||
public HttpResponse(ITcpClientBase client)
|
||||
{
|
||||
this.m_client = client;
|
||||
if (client==null)
|
||||
{
|
||||
this.m_canRead = false;
|
||||
this.m_canWrite = false;
|
||||
|
||||
return;
|
||||
}
|
||||
if (client.IsClient)
|
||||
{
|
||||
this.m_canRead = true;
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace TouchSocket.Http
|
||||
/// <inheritdoc/>
|
||||
public override void Connect(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
|
||||
if (this.Config.GetValue(HttpConfigExtensions.HttpProxyProperty) is HttpProxy httpProxy)
|
||||
{
|
||||
var proxyHost = httpProxy.Host;
|
||||
@@ -253,20 +254,13 @@ namespace TouchSocket.Http
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (this.m_waitData.Wait(millisecondsTimeout))
|
||||
return this.m_waitData.Wait(millisecondsTimeout) switch
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
WaitDataStatus.SetRunning => this.m_waitData.WaitResult,
|
||||
WaitDataStatus.Overtime => throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription()),
|
||||
WaitDataStatus.Canceled => throw new OperationCanceledException(),
|
||||
_ => throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription()),
|
||||
};
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -294,20 +288,13 @@ namespace TouchSocket.Http
|
||||
return default;
|
||||
}
|
||||
|
||||
switch (await this.m_waitDataAsync.WaitAsync(millisecondsTimeout))
|
||||
return await this.m_waitDataAsync.WaitAsync(millisecondsTimeout) switch
|
||||
{
|
||||
case WaitDataStatus.SetRunning:
|
||||
return this.m_waitData.WaitResult;
|
||||
|
||||
case WaitDataStatus.Overtime:
|
||||
throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription());
|
||||
case WaitDataStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case WaitDataStatus.Default:
|
||||
case WaitDataStatus.Disposed:
|
||||
default:
|
||||
throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription());
|
||||
}
|
||||
WaitDataStatus.SetRunning => this.m_waitData.WaitResult,
|
||||
WaitDataStatus.Overtime => throw new TimeoutException(TouchSocketHttpResource.Overtime.GetDescription()),
|
||||
WaitDataStatus.Canceled => throw new OperationCanceledException(),
|
||||
_ => throw new Exception(TouchSocketHttpResource.UnknownError.GetDescription()),
|
||||
};
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Http
|
||||
@@ -22,6 +23,7 @@ namespace TouchSocket.Http
|
||||
public class HttpSocketClient : SocketClient, IHttpSocketClient
|
||||
{
|
||||
private HttpContext m_httpContext;
|
||||
private InternalWebSocket m_webSocket;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
@@ -31,26 +33,93 @@ namespace TouchSocket.Http
|
||||
this.Protocol = Protocol.Http;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IWebSocket WebSocket { get => m_webSocket; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> SwitchProtocolToWebSocket(HttpContext httpContext)
|
||||
{
|
||||
if (this.m_webSocket is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (this.Protocol == Protocol.Http)
|
||||
{
|
||||
if (WSTools.TryGetResponse(httpContext.Request, httpContext.Response))
|
||||
{
|
||||
var args = new HttpContextEventArgs(new HttpContext(httpContext.Request, httpContext.Response))
|
||||
{
|
||||
IsPermitOperation = true
|
||||
};
|
||||
|
||||
var webSocket = new InternalWebSocket(this);
|
||||
|
||||
await this.PluginManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), webSocket, args).ConfigureAwait(false);
|
||||
|
||||
if (args.Context.Response.Responsed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (args.IsPermitOperation)
|
||||
{
|
||||
this.InitWebSocket(webSocket);
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
args.Context.Response.Build(byteBlock);
|
||||
await this.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
}
|
||||
_ = this.PluginManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), webSocket, new HttpContextEventArgs(httpContext))
|
||||
.ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Context.Response.SetStatus(403, "Forbidden");
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
args.Context.Response.Build(byteBlock);
|
||||
await this.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
this.Close("主动拒绝WebSocket连接");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Close("WebSocket连接协议不正确");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnConnecting(ConnectingEventArgs e)
|
||||
{
|
||||
this.SetDataHandlingAdapter(new HttpServerDataHandlingAdapter());
|
||||
this.SetAdapter(new HttpServerDataHandlingAdapter());
|
||||
await base.OnConnecting(e).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnDisconnected(DisconnectEventArgs e)
|
||||
{
|
||||
if (this.m_webSocket != null)
|
||||
{
|
||||
this.m_webSocket.IsHandshaked = false;
|
||||
_ = this.m_webSocket.TryInputReceiveAsync(null);
|
||||
}
|
||||
await base.OnDisconnected(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当收到到Http请求时。覆盖父类方法将不会触发插件。
|
||||
/// </summary>
|
||||
protected virtual async Task OnReceivedHttpRequest(HttpRequest request)
|
||||
{
|
||||
m_httpContext ??= new HttpContext(request);
|
||||
|
||||
if (this.PluginManager.GetPluginCount(nameof(IHttpPlugin.OnHttpRequest)) > 0)
|
||||
{
|
||||
var e = new HttpContextEventArgs(m_httpContext);
|
||||
|
||||
await this.PluginManager.RaiseAsync(nameof(IHttpPlugin.OnHttpRequest), this, e).ConfigureFalseAwait();
|
||||
m_httpContext.Response.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +128,48 @@ namespace TouchSocket.Http
|
||||
{
|
||||
if (e.RequestInfo is HttpRequest request)
|
||||
{
|
||||
m_httpContext ??= new HttpContext(request);
|
||||
await this.OnReceivedHttpRequest(request).ConfigureFalseAwait();
|
||||
m_httpContext.Response.Reset();
|
||||
}
|
||||
else if (this.m_webSocket != null && e.RequestInfo is WSDataFrame dataFrame)
|
||||
{
|
||||
e.Handled = true;
|
||||
await this.OnHandleWSDataFrame(dataFrame);
|
||||
return;
|
||||
}
|
||||
await base.ReceivedData(e).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
private void InitWebSocket(InternalWebSocket webSocket)
|
||||
{
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.Protocol = Protocol.WebSocket;
|
||||
this.m_webSocket = webSocket;
|
||||
}
|
||||
|
||||
private async Task OnHandleWSDataFrame(WSDataFrame dataFrame)
|
||||
{
|
||||
if (dataFrame.IsClose && this.GetValue(WebSocketFeature.AutoCloseProperty))
|
||||
{
|
||||
var msg = dataFrame.PayloadData?.ToString();
|
||||
await this.PluginManager.RaiseAsync(nameof(IWebSocketClosingPlugin.OnWebSocketClosing), this.m_webSocket, new MsgPermitEventArgs() { Message = msg });
|
||||
this.m_webSocket.Close(msg);
|
||||
return;
|
||||
}
|
||||
if (dataFrame.IsPing && this.GetValue(WebSocketFeature.AutoPongProperty))
|
||||
{
|
||||
this.m_webSocket.Pong();
|
||||
return;
|
||||
}
|
||||
if (this.m_webSocket.AllowAsyncRead)
|
||||
{
|
||||
if (await this.m_webSocket.TryInputReceiveAsync(dataFrame))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this.m_webSocket, new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Http
|
||||
@@ -19,5 +21,15 @@ namespace TouchSocket.Http
|
||||
/// </summary>
|
||||
public interface IHttpSocketClient : IHttpClientBase, ISocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 当该连接是WebSocket时,可获取该对象,否则为null。
|
||||
/// </summary>
|
||||
IWebSocket WebSocket { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 转化Protocol协议标识为<see cref="Protocol.WebSocket"/>
|
||||
/// </summary>
|
||||
/// <param name="httpContext">Http上下文</param>
|
||||
Task<bool> SwitchProtocolToWebSocket(HttpContext httpContext);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Http;Https;HttpServer;HttpClient;WebSocket;WebSocketServer;WebSocketClient;TouchSocket</PackageTags>
|
||||
<Description>这是一个基于Http1.1协议的组件库。它能提供Http服务器、客户端、以及WebSocket组件。功能上支持大文件下载、上传、以及多线程下载和断点续传,小文件form上传,WebApi声明和执行。所提供的Http客户端是基于连接的,可以捕获连接和断开连接等消息。
|
||||
|
||||
|
||||
@@ -18,63 +18,71 @@ using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
internal class InternalWebSocket : DisposableObject, IWebSocket
|
||||
internal sealed class InternalWebSocket : DisposableObject, IWebSocket
|
||||
{
|
||||
private readonly IHttpClientBase m_client;
|
||||
private bool m_receive;
|
||||
private readonly AsyncAutoResetEvent m_resetEventForComplateRead = new AsyncAutoResetEvent(false);
|
||||
private readonly AsyncAutoResetEvent m_resetEventForRead = new AsyncAutoResetEvent(false);
|
||||
private WSDataFrame m_dataFrame;
|
||||
|
||||
public InternalWebSocket(IHttpClientBase client, bool receive)
|
||||
private bool m_allowAsyncRead;
|
||||
private bool m_isCont;
|
||||
public InternalWebSocket(IHttpClientBase client)
|
||||
{
|
||||
this.m_client = client;
|
||||
this.m_receive = receive;
|
||||
}
|
||||
public bool AllowAsyncRead { get => m_allowAsyncRead; set => m_allowAsyncRead = value; }
|
||||
|
||||
public bool IsHandshaked => this.m_client.GetHandshaked();
|
||||
public bool IsHandshaked { get;set; }
|
||||
|
||||
public string Version => this.m_client.GetWebSocketVersion();
|
||||
public string Version { get; set; }
|
||||
|
||||
public IHttpClientBase Client => this.m_client;
|
||||
|
||||
public void Close(string msg)
|
||||
{
|
||||
this.m_client.CloseWithWS(msg);
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg))
|
||||
{
|
||||
this.Send(frame);
|
||||
}
|
||||
this.m_client.TryShutdown();
|
||||
this.m_client.SafeClose(msg);
|
||||
this.m_receive = false;
|
||||
this.m_allowAsyncRead = false;
|
||||
}
|
||||
|
||||
public async Task CloseAsync(string msg)
|
||||
{
|
||||
await this.m_client.CloseWithWSAsync(msg);
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg))
|
||||
{
|
||||
await this.SendAsync(frame);
|
||||
}
|
||||
this.m_client.TryShutdown();
|
||||
this.m_client.SafeClose(msg);
|
||||
this.m_receive = false;
|
||||
this.m_allowAsyncRead = false;
|
||||
}
|
||||
|
||||
public void Ping()
|
||||
{
|
||||
this.m_client.PingWS();
|
||||
Send(new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping });
|
||||
}
|
||||
|
||||
public Task PingAsync()
|
||||
public async Task PingAsync()
|
||||
{
|
||||
return this.m_client.PingWSAsync();
|
||||
await SendAsync(new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping });
|
||||
}
|
||||
|
||||
public void Pong()
|
||||
{
|
||||
this.m_client.PongWS();
|
||||
this.Send( new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong });
|
||||
}
|
||||
|
||||
public Task PongAsync()
|
||||
public async Task PongAsync()
|
||||
{
|
||||
return this.m_client.PongWSAsync();
|
||||
await this.SendAsync(new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong });
|
||||
}
|
||||
|
||||
public async Task<WebSocketReceiveResult> ReadAsync(CancellationToken token)
|
||||
{
|
||||
if (!this.m_receive)
|
||||
if (!this.m_allowAsyncRead)
|
||||
{
|
||||
return new WebSocketReceiveResult(this.ComplateRead, null);
|
||||
}
|
||||
@@ -82,10 +90,10 @@ namespace TouchSocket.Http.WebSockets
|
||||
return new WebSocketReceiveResult(this.ComplateRead, this.m_dataFrame);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
#if ValueTask
|
||||
public async ValueTask<WebSocketReceiveResult> ValueReadAsync(CancellationToken token)
|
||||
{
|
||||
if (!this.m_receive)
|
||||
if (!this.m_allowAsyncRead)
|
||||
{
|
||||
return new WebSocketReceiveResult(this.ComplateRead, null);
|
||||
}
|
||||
@@ -98,54 +106,144 @@ namespace TouchSocket.Http.WebSockets
|
||||
|
||||
public void Send(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(dataFrame, endOfMessage);
|
||||
WSDataType dataType;
|
||||
if (this.m_isCont)
|
||||
{
|
||||
dataType = WSDataType.Cont;
|
||||
if (endOfMessage)
|
||||
{
|
||||
m_isCont=false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataType = dataFrame.Opcode;
|
||||
if (!endOfMessage)
|
||||
{
|
||||
m_isCont = true;
|
||||
}
|
||||
}
|
||||
dataFrame.Opcode = dataType;
|
||||
using (var byteBlock = new ByteBlock(dataFrame.GetTotalSize()))
|
||||
{
|
||||
if (m_client.IsClient)
|
||||
{
|
||||
dataFrame.BuildRequest(byteBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataFrame.BuildResponse(byteBlock);
|
||||
}
|
||||
m_client.DefaultSend(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(string text, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(text, endOfMessage);
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Text }.AppendText(text))
|
||||
{
|
||||
this.Send(frame, endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SendAsync(string text, bool endOfMessage = true)
|
||||
public async Task SendAsync(string text, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(text, endOfMessage);
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Text }.AppendText(text))
|
||||
{
|
||||
await this.SendAsync(frame, endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(buffer, offset, length, endOfMessage);
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
frame.PayloadData = new ByteBlock(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.AppendBinary(buffer, offset, length);
|
||||
}
|
||||
this.Send(frame, endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(ByteBlock byteBlock, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(byteBlock, endOfMessage);
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
{
|
||||
frame.PayloadData = byteBlock;
|
||||
this.Send(frame, endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SendAsync(byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(buffer, endOfMessage);
|
||||
return this.SendAsync(buffer,0,buffer.Length, endOfMessage);
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.SendWithWS(buffer, endOfMessage);
|
||||
this.Send(buffer,0,buffer.Length, endOfMessage);
|
||||
}
|
||||
|
||||
public Task SendAsync(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
public async Task SendAsync(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(buffer, offset, length, endOfMessage);
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
{
|
||||
if (offset == 0)
|
||||
{
|
||||
frame.PayloadData = new ByteBlock(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.AppendBinary(buffer, offset, length);
|
||||
}
|
||||
await this.SendAsync(frame, endOfMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SendAsync(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
public async Task SendAsync(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(dataFrame, endOfMessage);
|
||||
WSDataType dataType;
|
||||
if (this.m_isCont)
|
||||
{
|
||||
dataType = WSDataType.Cont;
|
||||
if (endOfMessage)
|
||||
{
|
||||
m_isCont = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataType = dataFrame.Opcode;
|
||||
if (!endOfMessage)
|
||||
{
|
||||
m_isCont = true;
|
||||
}
|
||||
}
|
||||
dataFrame.Opcode = dataType;
|
||||
using (var byteBlock = new ByteBlock(dataFrame.GetTotalSize()))
|
||||
{
|
||||
if (m_client.IsClient)
|
||||
{
|
||||
dataFrame.BuildRequest(byteBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataFrame.BuildResponse(byteBlock);
|
||||
}
|
||||
await m_client.DefaultSendAsync(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 发送
|
||||
|
||||
public async Task<bool> TryInputReceiveAsync(WSDataFrame dataFrame)
|
||||
internal async Task<bool> TryInputReceiveAsync(WSDataFrame dataFrame)
|
||||
{
|
||||
if (!this.m_receive)
|
||||
if (!this.m_allowAsyncRead)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -164,7 +262,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
this.m_client.RemoveValue(WebSocketClientExtension.WebSocketProperty);
|
||||
//this.m_client.RemoveValue(WebSocketClientExtension.WebSocketProperty);
|
||||
this.m_resetEventForComplateRead.SafeDispose();
|
||||
this.m_resetEventForRead.SafeDispose();
|
||||
this.m_dataFrame = null;
|
||||
|
||||
19
src/TouchSocket.Http/WebSockets/Common/WebSocketOption.cs
Normal file
19
src/TouchSocket.Http/WebSockets/Common/WebSocketOption.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocket配置
|
||||
/// </summary>
|
||||
public class WebSocketOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 版本
|
||||
/// </summary>
|
||||
public string Version { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,9 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// WebSocketReceiveResult
|
||||
/// </summary>
|
||||
public struct WebSocketReceiveResult : IDisposable
|
||||
public readonly struct WebSocketReceiveResult : IDisposable
|
||||
{
|
||||
private Action m_disAction;
|
||||
private readonly Action m_disAction;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocketReceiveResult
|
||||
@@ -41,7 +41,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// WebSocket数据帧
|
||||
/// </summary>
|
||||
public WSDataFrame DataFrame { get; private set; }
|
||||
public WSDataFrame DataFrame { get;}
|
||||
|
||||
/// <summary>
|
||||
/// 连接已关闭
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// SetupClientWebSocket
|
||||
/// </summary>
|
||||
public abstract class SetupClientWebSocket : SetupConfigObject, IClient, ICloseObject, IConnectObject
|
||||
{
|
||||
/// <summary>
|
||||
/// SetupClientWebSocket
|
||||
/// </summary>
|
||||
public SetupClientWebSocket()
|
||||
{
|
||||
this.m_receiveCounter = new ValueCounter
|
||||
{
|
||||
Period = TimeSpan.FromSeconds(1),
|
||||
OnPeriod = this.OnReceivePeriod
|
||||
};
|
||||
this.m_sendCounter = new ValueCounter
|
||||
{
|
||||
Period = TimeSpan.FromSeconds(1),
|
||||
OnPeriod = this.OnSendPeriod
|
||||
};
|
||||
}
|
||||
|
||||
#region 字段
|
||||
|
||||
private readonly SemaphoreSlim m_semaphoreForConnect = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim m_semaphoreForSend = new SemaphoreSlim(1, 1);
|
||||
private ClientWebSocket m_client;
|
||||
private bool m_isHandshaked;
|
||||
private int m_receiveBufferSize = 1024 * 10;
|
||||
private ValueCounter m_receiveCounter;
|
||||
private int m_sendBufferSize = 1024 * 10;
|
||||
private ValueCounter m_sendCounter;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
#region 连接
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void Connect(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
this.ConnectAsync(millisecondsTimeout, token).GetFalseAwaitResult();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task ConnectAsync(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreForConnect.WaitAsync();
|
||||
if (this.m_isHandshaked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.m_client == null || this.m_client.State != WebSocketState.Open)
|
||||
{
|
||||
this.m_client.SafeDispose();
|
||||
this.m_client = new ClientWebSocket();
|
||||
await this.m_client.ConnectAsync(this.RemoteIPHost, token);
|
||||
_ = this.BeginReceive();
|
||||
}
|
||||
|
||||
this.m_isHandshaked = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.m_semaphoreForConnect.Release();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 连接
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastReceivedTime => this.m_receiveCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => this.m_sendCounter.LastIncrement;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get; set; } = Protocol.WebSocket;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPHost RemoteIPHost { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已完成连接
|
||||
/// </summary>
|
||||
protected bool ProtectedIsHandshaked { get => this.m_isHandshaked;}
|
||||
|
||||
/// <summary>
|
||||
/// 通讯实际客户端
|
||||
/// </summary>
|
||||
protected ClientWebSocket Client { get => this.m_client;}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void Close(string msg)
|
||||
{
|
||||
this.BreakOut(msg, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 中断连接
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="manual"></param>
|
||||
protected void BreakOut(string msg, bool manual)
|
||||
{
|
||||
lock (this.m_semaphoreForConnect)
|
||||
{
|
||||
if (this.m_isHandshaked)
|
||||
{
|
||||
this.m_isHandshaked = false;
|
||||
this.m_client.CloseAsync(WebSocketCloseStatus.NormalClosure, msg, CancellationToken.None);
|
||||
this.m_client.SafeDispose();
|
||||
|
||||
this.OnDisconnected(new DisconnectEventArgs(manual, msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (this.DisposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (disposing)
|
||||
{
|
||||
this.BreakOut($"调用{nameof(Dispose)}", true);
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
protected override void LoadConfig(TouchSocketConfig config)
|
||||
{
|
||||
this.RemoteIPHost = config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 已断开连接。
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected abstract void OnDisconnected(DisconnectEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// 收到数据
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract Task OnReceived(System.Net.WebSockets.WebSocketReceiveResult result, ByteBlock byteBlock);
|
||||
|
||||
private async Task BeginReceive()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
using (var byteBlock = new ByteBlock(this.m_receiveBufferSize))
|
||||
{
|
||||
var result = await this.m_client.ReceiveAsync(new ArraySegment<byte>(byteBlock.Buffer, 0, byteBlock.Capacity), default);
|
||||
if (result.Count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
byteBlock.SetLength(result.Count);
|
||||
this.m_receiveCounter.Increment(result.Count);
|
||||
|
||||
await this.OnReceived(result, byteBlock).ConfigureFalseAwait();
|
||||
}
|
||||
}
|
||||
|
||||
this.BreakOut("远程终端主动关闭", false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.BreakOut(ex.Message, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceivePeriod(long value)
|
||||
{
|
||||
this.m_receiveBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
}
|
||||
|
||||
private void OnSendPeriod(long value)
|
||||
{
|
||||
this.m_sendBufferSize = TouchSocketUtility.HitBufferLength(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
@@ -42,8 +43,16 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// WebSocket用户终端。
|
||||
/// </summary>
|
||||
public class WebSocketClientBase : HttpClientBase, IWebSocketClient
|
||||
public class WebSocketClientBase : IWebSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocket用户终端
|
||||
/// </summary>
|
||||
public WebSocketClientBase()
|
||||
{
|
||||
m_client = new PrivateHttpClient(this.OnReceivedWSDataFrame);
|
||||
}
|
||||
|
||||
#region Connect
|
||||
|
||||
/// <summary>
|
||||
@@ -52,23 +61,25 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <exception cref="WebSocketConnectException"></exception>
|
||||
public override void Connect(int millisecondsTimeout, CancellationToken token)
|
||||
public virtual void Connect(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.m_semaphoreSlim.Wait(token);
|
||||
if (!this.Online)
|
||||
if (!this.m_client.Online)
|
||||
{
|
||||
base.Connect(millisecondsTimeout, token);
|
||||
this.m_client.Connect(millisecondsTimeout, token);
|
||||
}
|
||||
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var option = this.m_client.Config.GetValue(WebSocketConfigExtension.WebSocketOptionProperty);
|
||||
|
||||
var iPHost = this.m_client.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var url = iPHost.PathAndQuery;
|
||||
var request = WSTools.GetWSRequest(this.RemoteIPHost.Host, url, this.GetWebSocketVersion(), out var base64Key);
|
||||
var request = WSTools.GetWSRequest(this.m_client.RemoteIPHost.Host, url, option.Version, out var base64Key);
|
||||
this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)))
|
||||
.GetFalseAwaitResult();
|
||||
|
||||
var response = this.Request(request, millisecondsTimeout: millisecondsTimeout, token: token);
|
||||
var response = this.m_client.Request(request, millisecondsTimeout: millisecondsTimeout, token: token);
|
||||
if (response.StatusCode != 101)
|
||||
{
|
||||
throw new WebSocketConnectException($"协议升级失败,信息:{response.StatusMessage},更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response));
|
||||
@@ -76,12 +87,12 @@ namespace TouchSocket.Http.WebSockets
|
||||
var accept = response.Headers.Get("sec-websocket-accept").Trim();
|
||||
if (accept.IsNullOrEmpty() || !accept.Equals(WSTools.CalculateBase64Key(base64Key).Trim(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
this.MainSocket.SafeDispose();
|
||||
this.m_client.MainSocket.SafeDispose();
|
||||
throw new WebSocketConnectException($"WS服务器返回的应答码不正确,更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response));
|
||||
}
|
||||
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, true);
|
||||
this.m_client.InitWebSocket();
|
||||
|
||||
response.Flag = true;
|
||||
Task.Factory.StartNew(this.PrivateOnHandshaked, new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
}
|
||||
@@ -92,23 +103,25 @@ namespace TouchSocket.Http.WebSockets
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task ConnectAsync(int millisecondsTimeout, CancellationToken token)
|
||||
public virtual async Task ConnectAsync(int millisecondsTimeout, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.m_semaphoreSlim.WaitAsync(millisecondsTimeout, token);
|
||||
if (!this.Online)
|
||||
if (!this.m_client.Online)
|
||||
{
|
||||
await base.ConnectAsync(millisecondsTimeout, token);
|
||||
await this.m_client.ConnectAsync(millisecondsTimeout, token);
|
||||
}
|
||||
|
||||
var iPHost = this.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var option = this.m_client.Config.GetValue(WebSocketConfigExtension.WebSocketOptionProperty);
|
||||
|
||||
var iPHost = this.m_client.Config.GetValue(TouchSocketConfigExtension.RemoteIPHostProperty);
|
||||
var url = iPHost.PathAndQuery;
|
||||
var request = WSTools.GetWSRequest(this.RemoteIPHost.Host, url, this.GetWebSocketVersion(), out var base64Key);
|
||||
var request = WSTools.GetWSRequest(this.m_client.RemoteIPHost.Host, url, option.Version, out var base64Key);
|
||||
|
||||
await this.OnHandshaking(new HttpContextEventArgs(new HttpContext(request)));
|
||||
|
||||
var response = await this.RequestAsync(request, millisecondsTimeout: millisecondsTimeout, token: token);
|
||||
var response = await this.m_client.RequestAsync(request, millisecondsTimeout: millisecondsTimeout, token: token);
|
||||
if (response.StatusCode != 101)
|
||||
{
|
||||
throw new WebSocketConnectException($"协议升级失败,信息:{response.StatusMessage},更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response));
|
||||
@@ -116,12 +129,12 @@ namespace TouchSocket.Http.WebSockets
|
||||
var accept = response.Headers.Get("sec-websocket-accept").Trim();
|
||||
if (accept.IsNullOrEmpty() || !accept.Equals(WSTools.CalculateBase64Key(base64Key).Trim(), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
this.MainSocket.SafeDispose();
|
||||
this.m_client.MainSocket.SafeDispose();
|
||||
throw new WebSocketConnectException($"WS服务器返回的应答码不正确,更多信息请捕获WebSocketConnectException异常,获得HttpContext得知。", new HttpContext(request, response));
|
||||
}
|
||||
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, true);
|
||||
this.m_client.InitWebSocket();
|
||||
|
||||
response.Flag = true;
|
||||
_ = Task.Factory.StartNew(this.PrivateOnHandshaked, new HttpContextEventArgs(new HttpContext(request, response)));
|
||||
}
|
||||
@@ -136,11 +149,24 @@ namespace TouchSocket.Http.WebSockets
|
||||
#region 字段
|
||||
|
||||
private readonly SemaphoreSlim m_semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
private PrivateHttpClient m_client;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
///// <inheritdoc/>
|
||||
//public IWebSocket WebSocket => m_client.WebSocket;
|
||||
|
||||
#region 事件
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool AllowAsyncRead { get => this.m_client.WebSocket.AllowAsyncRead; set => this.m_client.WebSocket.AllowAsyncRead = value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IHttpClientBase Client => this.m_client;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TouchSocketConfig Config => ((IConfigObject)this.m_client).Config;
|
||||
|
||||
/// <summary>
|
||||
/// 表示完成握手后。
|
||||
/// </summary>
|
||||
@@ -151,10 +177,29 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
public HttpContextEventHandler<WebSocketClientBase> Handshaking { get; set; }
|
||||
|
||||
private Task PrivateOnHandshaked(object obj)
|
||||
{
|
||||
return this.OnHandshaked((HttpContextEventArgs)obj);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public bool IsHandshaked => this.m_client.WebSocket.IsHandshaked;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastReceivedTime => ((IClient)this.m_client).LastReceivedTime;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastSendTime => ((IClient)this.m_client).LastSendTime;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILog Logger { get => ((ILoggerObject)this.m_client).Logger; set => ((ILoggerObject)this.m_client).Logger = value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPluginManager PluginManager => ((IPluginObject)this.m_client).PluginManager;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Protocol Protocol { get => ((IClient)this.m_client).Protocol; set => ((IClient)this.m_client).Protocol = value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IResolver Resolver => ((IResolverObject)this.m_client).Resolver;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Version => this.m_client.WebSocket.Version;
|
||||
|
||||
/// <summary>
|
||||
/// 表示完成握手后。
|
||||
@@ -174,7 +219,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
await this.m_client.PluginManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -195,57 +240,167 @@ namespace TouchSocket.Http.WebSockets
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.PluginManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), this, e).ConfigureFalseAwait();
|
||||
await this.m_client.PluginManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), this, e).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
private Task PrivateOnHandshaked(object obj)
|
||||
{
|
||||
return this.OnHandshaked((HttpContextEventArgs)obj);
|
||||
}
|
||||
|
||||
#endregion 事件
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ReceivedData(ReceivedDataEventArgs e)
|
||||
public void Close(string msg)
|
||||
{
|
||||
if (this.GetHandshaked())
|
||||
{
|
||||
var dataFrame = (WSDataFrame)e.RequestInfo;
|
||||
|
||||
if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame).ConfigureFalseAwait())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.OnReceivedWSDataFrame(new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
response.Flag = false;
|
||||
await base.ReceivedData(e);
|
||||
SpinWait.SpinUntil(() =>
|
||||
{
|
||||
return (bool)response.Flag;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
await base.ReceivedData(e);
|
||||
this.m_client.WebSocket.Close(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override async Task OnDisconnected(DisconnectEventArgs e)
|
||||
public void Dispose()
|
||||
{
|
||||
this.SetValue(WebSocketFeature.HandshakedProperty, false);
|
||||
if (this.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
_ = internalWebSocket.TryInputReceiveAsync(null);
|
||||
}
|
||||
await base.OnDisconnected(e);
|
||||
((IDisposable)this.m_client).Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TValue GetValue<TValue>(IDependencyProperty<TValue> dp)
|
||||
{
|
||||
return ((IDependencyObject)this.m_client).GetValue(dp);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HasValue<TValue>(IDependencyProperty<TValue> dp)
|
||||
{
|
||||
return ((IDependencyObject)this.m_client).HasValue(dp);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Ping()
|
||||
{
|
||||
this.m_client.WebSocket.Ping();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task PingAsync()
|
||||
{
|
||||
return this.m_client.WebSocket.PingAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Pong()
|
||||
{
|
||||
this.m_client.WebSocket.Pong();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task PongAsync()
|
||||
{
|
||||
return this.m_client.WebSocket.PongAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<WebSocketReceiveResult> ReadAsync(CancellationToken token)
|
||||
{
|
||||
return this.m_client.WebSocket.ReadAsync(token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DependencyObject RemoveValue<TValue>(IDependencyProperty<TValue> dp)
|
||||
{
|
||||
return ((IDependencyObject)this.m_client).RemoveValue(dp);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Send(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.WebSocket.Send(dataFrame, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Send(string text, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.WebSocket.Send(text, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Send(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.WebSocket.Send(buffer, offset, length, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Send(ByteBlock byteBlock, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.WebSocket.Send(byteBlock, endOfMessage);
|
||||
}
|
||||
|
||||
public void Send(byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
this.m_client.WebSocket.Send(buffer, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task SendAsync(WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.WebSocket.SendAsync(dataFrame, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task SendAsync(string text, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.WebSocket.SendAsync(text, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task SendAsync(byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.WebSocket.SendAsync(buffer, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task SendAsync(byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
return this.m_client.WebSocket.SendAsync(buffer, offset, length, endOfMessage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Setup(TouchSocketConfig config)
|
||||
{
|
||||
((ISetupConfigObject)this.m_client).Setup(config);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task SetupAsync(TouchSocketConfig config)
|
||||
{
|
||||
return ((ISetupConfigObject)this.m_client).SetupAsync(config);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DependencyObject SetValue<TValue>(IDependencyProperty<TValue> dp, TValue value)
|
||||
{
|
||||
return ((IDependencyObject)this.m_client).SetValue(dp, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetValue<TValue>(IDependencyProperty<TValue> dp, out TValue value)
|
||||
{
|
||||
return ((IDependencyObject)this.m_client).TryGetValue(dp, out value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryRemoveValue<TValue>(IDependencyProperty<TValue> dp, out TValue value)
|
||||
{
|
||||
return ((IDependencyObject)this.m_client).TryRemoveValue(dp, out value);
|
||||
}
|
||||
|
||||
#if ValueTask
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<WebSocketReceiveResult> ValueReadAsync(CancellationToken token)
|
||||
{
|
||||
return await this.m_client.WebSocket.ValueReadAsync(token);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 当收到WS数据时。
|
||||
/// </summary>
|
||||
@@ -253,7 +408,77 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <returns></returns>
|
||||
protected virtual async Task OnReceivedWSDataFrame(WSDataFrameEventArgs e)
|
||||
{
|
||||
await this.PluginManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, e).ConfigureFalseAwait();
|
||||
await this.m_client.PluginManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this, e).ConfigureFalseAwait();
|
||||
}
|
||||
|
||||
#region InternalClass
|
||||
|
||||
private class PrivateHttpClient : HttpClientBase
|
||||
{
|
||||
private readonly InternalWebSocket m_webSocket;
|
||||
|
||||
private Func<WSDataFrameEventArgs, Task> m_func;
|
||||
|
||||
public PrivateHttpClient(Func<WSDataFrameEventArgs, Task> func)
|
||||
{
|
||||
this.m_webSocket = new InternalWebSocket(this);
|
||||
this.m_func = func;
|
||||
}
|
||||
|
||||
public InternalWebSocket WebSocket { get => m_webSocket; }
|
||||
|
||||
public void InitWebSocket()
|
||||
{
|
||||
this.SetAdapter(new WebSocketDataHandlingAdapter());
|
||||
this.Protocol = Protocol.WebSocket;
|
||||
this.m_webSocket.IsHandshaked = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override async Task OnDisconnected(DisconnectEventArgs e)
|
||||
{
|
||||
this.m_webSocket.IsHandshaked = false;
|
||||
if (this.m_webSocket.AllowAsyncRead)
|
||||
{
|
||||
_ = this.m_webSocket.TryInputReceiveAsync(null);
|
||||
}
|
||||
await base.OnDisconnected(e);
|
||||
}
|
||||
|
||||
protected override async Task ReceivedData(ReceivedDataEventArgs e)
|
||||
{
|
||||
if (this.m_webSocket.IsHandshaked)
|
||||
{
|
||||
var dataFrame = (WSDataFrame)e.RequestInfo;
|
||||
|
||||
if (this.m_webSocket.AllowAsyncRead)
|
||||
{
|
||||
if (await this.m_webSocket.TryInputReceiveAsync(dataFrame).ConfigureFalseAwait())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.m_func(new WSDataFrameEventArgs(dataFrame));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.RequestInfo is HttpResponse response)
|
||||
{
|
||||
response.Flag = false;
|
||||
await base.ReceivedData(e);
|
||||
SpinWait.SpinUntil(() =>
|
||||
{
|
||||
return (bool)response.Flag;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
await base.ReceivedData(e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion InternalClass
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
|
||||
@@ -22,19 +23,23 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
#region DependencyProperty
|
||||
|
||||
[Obsolete("此配置已被弃用",true)]
|
||||
private static readonly DependencyProperty<bool> IsContProperty =
|
||||
DependencyProperty<bool>.Register("IsCont", false);
|
||||
|
||||
[Obsolete("此配置已被弃用", true)]
|
||||
private static void SetIsCont(this IHttpClientBase client, bool value)
|
||||
{
|
||||
client.SetValue(IsContProperty, value);
|
||||
}
|
||||
|
||||
[Obsolete("此配置已被弃用", true)]
|
||||
private static bool GetIsCont(this IHttpClientBase client)
|
||||
{
|
||||
return client.GetValue(IsContProperty);
|
||||
}
|
||||
|
||||
[Obsolete("此配置已被弃用", true)]
|
||||
internal static readonly DependencyProperty<InternalWebSocket> WebSocketProperty =
|
||||
DependencyProperty<InternalWebSocket>.Register("WebSocket", null);
|
||||
|
||||
@@ -47,12 +52,13 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="allowReceive"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,请直接获取WebSocket属性",true)]
|
||||
public static IWebSocket GetWebSocket(this IHttpClientBase client, bool allowReceive = true)
|
||||
{
|
||||
var websocket = client.GetValue(WebSocketProperty);
|
||||
if (websocket == null)
|
||||
{
|
||||
websocket = new InternalWebSocket(client, allowReceive);
|
||||
websocket = new InternalWebSocket(client);
|
||||
client.SetValue(WebSocketProperty, websocket);
|
||||
}
|
||||
return websocket;
|
||||
@@ -62,6 +68,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// 清除显式WebSocket终端。
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
[Obsolete("此配置已被弃用", true)]
|
||||
public static void ClearWebSocket(this IHttpClientBase client)
|
||||
{
|
||||
client.RemoveValue(WebSocketProperty);
|
||||
@@ -75,6 +82,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void CloseWithWS(this IHttpClientBase client, string msg)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg))
|
||||
@@ -89,6 +97,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task CloseWithWSAsync(this IHttpClientBase client, string msg)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Close }.AppendText(msg))
|
||||
@@ -102,6 +111,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,请直接获取IsHandshaked属性,或者WebSocket.IsHandshaked", true)]
|
||||
public static bool GetHandshaked(this IHttpClientBase client)
|
||||
{
|
||||
return client.GetValue(WebSocketFeature.HandshakedProperty);
|
||||
@@ -112,6 +122,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,请直接获取Version属性,或者WebSocket.Version", true)]
|
||||
public static string GetWebSocketVersion(this IHttpClientBase client)
|
||||
{
|
||||
return client.GetValue(WebSocketFeature.WebSocketVersionProperty);
|
||||
@@ -122,6 +133,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void PingWS(this IHttpClientBase client)
|
||||
{
|
||||
SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping });
|
||||
@@ -132,6 +144,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task PingWSAsync(this IHttpClientBase client)
|
||||
{
|
||||
return SendWithWSAsync(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Ping });
|
||||
@@ -142,6 +155,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void PongWS(this IHttpClientBase client)
|
||||
{
|
||||
SendWithWS(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong });
|
||||
@@ -152,6 +166,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task PongWSAsync(this IHttpClientBase client)
|
||||
{
|
||||
return SendWithWSAsync(client, new WSDataFrame() { FIN = true, Opcode = WSDataType.Pong });
|
||||
@@ -160,6 +175,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// 设置WebSocket版本号。
|
||||
/// </summary>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void SetWebSocketVersion(this IHttpClientBase client, string value)
|
||||
{
|
||||
client.SetValue(WebSocketFeature.WebSocketVersionProperty, value);
|
||||
@@ -175,6 +191,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void SendWithWS(this IHttpClientBase client, byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
@@ -197,6 +214,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void SendWithWS(this IHttpClientBase client, ByteBlock byteBlock, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
@@ -212,6 +230,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void SendWithWS(this IHttpClientBase client, byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
SendWithWS(client, buffer, 0, buffer.Length, endOfMessage);
|
||||
@@ -223,6 +242,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void SendWithWS(this IHttpClientBase client, string text, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Text }.AppendText(text))
|
||||
@@ -237,6 +257,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static void SendWithWS(this IHttpClientBase client, WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
var isCont = client.GetIsCont();
|
||||
@@ -285,6 +306,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, byte[] buffer, int offset, int length, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = endOfMessage, Opcode = WSDataType.Binary })
|
||||
@@ -307,6 +329,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, byte[] buffer, bool endOfMessage = true)
|
||||
{
|
||||
return SendWithWSAsync(client, buffer, 0, buffer.Length, endOfMessage);
|
||||
@@ -318,6 +341,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, string text, bool endOfMessage = true)
|
||||
{
|
||||
using (var frame = new WSDataFrame() { FIN = true, Opcode = WSDataType.Text }.AppendText(text))
|
||||
@@ -332,6 +356,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <param name="client"></param>
|
||||
/// <param name="dataFrame"></param>
|
||||
/// <param name="endOfMessage"></param>
|
||||
[Obsolete("此配置已被弃用,服务器请client.WebSocket.Sned执行,客户端可直接Send", true)]
|
||||
public static Task SendWithWSAsync(this IHttpClientBase client, WSDataFrame dataFrame, bool endOfMessage = true)
|
||||
{
|
||||
var isCont = client.GetIsCont();
|
||||
|
||||
@@ -44,5 +44,23 @@ namespace TouchSocket.Sockets
|
||||
{
|
||||
return BuildWithWebSocketClient<WebSocketClient>(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket配置属性
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<WebSocketOption> WebSocketOptionProperty =
|
||||
DependencyProperty<WebSocketOption>.Register("WebSocketOption", new WebSocketOption());
|
||||
|
||||
/// <summary>
|
||||
/// 设置WebSocket的相关配置
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static TouchSocketConfig SetWebSocketOption(this TouchSocketConfig config, WebSocketOption value)
|
||||
{
|
||||
config.SetValue(WebSocketOptionProperty, value);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,90 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在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://touchsocket.net/
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
////------------------------------------------------------------------------------
|
||||
//// 此代码版权(除特别声明或在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://touchsocket.net/
|
||||
//// 交流QQ群:234762506
|
||||
//// 感谢您的下载和使用
|
||||
////------------------------------------------------------------------------------
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
//using System.Threading.Tasks;
|
||||
//using TouchSocket.Core;
|
||||
//using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// WebSocketServerExtensions
|
||||
/// </summary>
|
||||
public static class WebSocketServerExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 转化Protocol协议标识为<see cref="Protocol.WebSocket"/>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="httpContext">Http上下文</param>
|
||||
public static async Task<bool> SwitchProtocolToWebSocket<TClient>(this TClient client, HttpContext httpContext) where TClient : IHttpSocketClient
|
||||
{
|
||||
if (client.Protocol == Protocol.WebSocket)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (client.Protocol == Protocol.Http)
|
||||
{
|
||||
if (WSTools.TryGetResponse(httpContext.Request, httpContext.Response))
|
||||
{
|
||||
var args = new HttpContextEventArgs(new HttpContext(httpContext.Request, httpContext.Response))
|
||||
{
|
||||
IsPermitOperation = true
|
||||
};
|
||||
await client.PluginManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), client, args).ConfigureAwait(false);
|
||||
//namespace TouchSocket.Http.WebSockets
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// WebSocketServerExtensions
|
||||
// /// </summary>
|
||||
// public static class WebSocketServerExtension
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 转化Protocol协议标识为<see cref="Protocol.WebSocket"/>
|
||||
// /// </summary>
|
||||
// /// <param name="socketClient"></param>
|
||||
// /// <param name="httpContext">Http上下文</param>
|
||||
// public static async Task<bool> SwitchProtocolToWebSocket(this IHttpSocketClient socketClient, HttpContext httpContext)
|
||||
// {
|
||||
// if (socketClient is not HttpSocketClient client)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (client.Protocol == Protocol.WebSocket)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// if (client.Protocol == Protocol.Http)
|
||||
// {
|
||||
// if (WSTools.TryGetResponse(httpContext.Request, httpContext.Response))
|
||||
// {
|
||||
// var args = new HttpContextEventArgs(new HttpContext(httpContext.Request, httpContext.Response))
|
||||
// {
|
||||
// IsPermitOperation = true
|
||||
// };
|
||||
// await client.PluginManager.RaiseAsync(nameof(IWebSocketHandshakingPlugin.OnWebSocketHandshaking), client, args).ConfigureAwait(false);
|
||||
|
||||
if (args.Context.Response.Responsed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (args.IsPermitOperation)
|
||||
{
|
||||
client.SetDataHandlingAdapter(new WebSocketDataHandlingAdapter());
|
||||
client.Protocol = Protocol.WebSocket;
|
||||
client.SetValue(WebSocketFeature.HandshakedProperty, true);//设置握手状态
|
||||
// if (args.Context.Response.Responsed)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (args.IsPermitOperation)
|
||||
// {
|
||||
// client.InitWebSocket();
|
||||
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
args.Context.Response.Build(byteBlock);
|
||||
await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
}
|
||||
_ = client.PluginManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext))
|
||||
.ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Context.Response.SetStatus(403, "Forbidden");
|
||||
using (var byteBlock = new ByteBlock())
|
||||
{
|
||||
args.Context.Response.Build(byteBlock);
|
||||
await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
}
|
||||
// //client.SetDataHandlingAdapter(new WebSocketDataHandlingAdapter());
|
||||
// //client.Protocol = Protocol.WebSocket;
|
||||
// //client.SetValue(WebSocketFeature.HandshakedProperty, true);//设置握手状态
|
||||
|
||||
client.Close("主动拒绝WebSocket连接");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client.Close("WebSocket连接协议不正确");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// using (var byteBlock = new ByteBlock())
|
||||
// {
|
||||
// args.Context.Response.Build(byteBlock);
|
||||
// await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
// }
|
||||
// _ = client.PluginManager.RaiseAsync(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), client, new HttpContextEventArgs(httpContext))
|
||||
// .ConfigureAwait(false);
|
||||
// return true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// args.Context.Response.SetStatus(403, "Forbidden");
|
||||
// using (var byteBlock = new ByteBlock())
|
||||
// {
|
||||
// args.Context.Response.Build(byteBlock);
|
||||
// await client.DefaultSendAsync(byteBlock).ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// client.Close("主动拒绝WebSocket连接");
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// client.Close("WebSocket连接协议不正确");
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -29,11 +29,14 @@ namespace TouchSocket.Http.WebSockets
|
||||
string Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送Close报文
|
||||
/// 允许异步Read读取
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
Task CloseAsync(string msg);
|
||||
bool AllowAsyncRead { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用的Http客户端
|
||||
/// </summary>
|
||||
IHttpClientBase Client { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送Ping报文。
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户终端接口
|
||||
/// </summary>
|
||||
public interface IWebSocketClient : IHttpClient
|
||||
public interface IWebSocketClient : IClient,ICloseObject, ILoggerObject, ISetupConfigObject, IConnectObject, IWebSocket
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketClosingPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketClosingPlugin<in TClient> : IPlugin where TClient : IHttpClientBase
|
||||
public interface IWebSocketClosingPlugin<in TClient> : IPlugin where TClient : IWebSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示收到断开连接报文。如果对方直接断开连接,此方法则不会触发。
|
||||
@@ -31,7 +31,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketClosingPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketClosingPlugin : IWebSocketClosingPlugin<IHttpClientBase>
|
||||
public interface IWebSocketClosingPlugin : IWebSocketClosingPlugin<IWebSocket>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketHandshakedPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketHandshakedPlugin<in TClient> : IPlugin where TClient : IHttpClientBase
|
||||
public interface IWebSocketHandshakedPlugin<in TClient> : IPlugin where TClient : IWebSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示完成握手后。
|
||||
@@ -32,7 +32,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketHandshakedPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketHandshakedPlugin : IWebSocketHandshakedPlugin<IHttpClientBase>
|
||||
public interface IWebSocketHandshakedPlugin : IWebSocketHandshakedPlugin<IWebSocket>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketHandshakingPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketHandshakingPlugin<in TClient> : IPlugin where TClient : IHttpClientBase
|
||||
public interface IWebSocketHandshakingPlugin<in TClient> : IPlugin where TClient : IWebSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示在即将握手连接时。
|
||||
@@ -32,7 +32,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketHandshakingPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketHandshakingPlugin : IWebSocketHandshakingPlugin<IHttpClientBase>
|
||||
public interface IWebSocketHandshakingPlugin : IWebSocketHandshakingPlugin<IWebSocket>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketReceivedPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketReceivedPlugin<in TClient> : IPlugin where TClient : IHttpClientBase
|
||||
public interface IWebSocketReceivedPlugin<in TClient> : IPlugin where TClient : IWebSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// 当收到WS数据时。
|
||||
@@ -32,7 +32,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// IWebSocketReceivedPlugin
|
||||
/// </summary>
|
||||
public interface IWebSocketReceivedPlugin : IWebSocketReceivedPlugin<IHttpClientBase>
|
||||
public interface IWebSocketReceivedPlugin : IWebSocketReceivedPlugin<IWebSocket>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// WS命令行插件。
|
||||
/// </summary>
|
||||
public abstract class WebSocketCommandLinePlugin : PluginBase, IWebSocketReceivedPlugin
|
||||
public abstract class WebSocketCommandLinePlugin : PluginBase
|
||||
{
|
||||
private readonly ILog m_logger;
|
||||
private readonly Dictionary<string, Method> m_pairs = new Dictionary<string, Method>();
|
||||
@@ -44,6 +44,14 @@ namespace TouchSocket.Http.WebSockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Loaded(IPluginManager pluginManager)
|
||||
{
|
||||
base.Loaded(pluginManager);
|
||||
|
||||
pluginManager.Add<IWebSocket, WSDataFrameEventArgs>(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this.OnWebSocketReceived);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字符串转换器,默认支持基础类型和Json。可以自定义。
|
||||
/// </summary>
|
||||
@@ -65,7 +73,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task OnWebSocketReceived(IHttpClientBase client, WSDataFrameEventArgs e)
|
||||
private async Task OnWebSocketReceived(IWebSocket webSocket, WSDataFrameEventArgs e)
|
||||
{
|
||||
if (e.DataFrame.Opcode == WSDataType.Text)
|
||||
{
|
||||
@@ -81,7 +89,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
if (ps[i].ParameterType.IsInterface && typeof(ITcpClientBase).IsAssignableFrom(ps[i].ParameterType))
|
||||
{
|
||||
os[i] = client;
|
||||
os[i] = webSocket.Client;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -114,28 +122,14 @@ namespace TouchSocket.Http.WebSockets
|
||||
|
||||
if (method.HasReturn)
|
||||
{
|
||||
if (client is HttpClient httpClient)
|
||||
{
|
||||
httpClient.SendWithWS(this.Converter.Serialize(null, result));
|
||||
}
|
||||
else if (client is HttpSocketClient httpSocketClient)
|
||||
{
|
||||
httpSocketClient.SendWithWS(this.Converter.Serialize(null, result));
|
||||
}
|
||||
webSocket.Send(this.Converter.Serialize(null, result));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (this.ReturnException)
|
||||
{
|
||||
if (client is HttpClient httpClient)
|
||||
{
|
||||
httpClient.SendWithWS(this.Converter.Serialize(null, ex.Message));
|
||||
}
|
||||
else if (client is HttpSocketClient httpSocketClient)
|
||||
{
|
||||
httpSocketClient.SendWithWS(this.Converter.Serialize(null, ex.Message));
|
||||
}
|
||||
webSocket.Send(this.Converter.Serialize(null, ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,15 +27,29 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// <summary>
|
||||
/// 表示是否完成WS握手
|
||||
/// </summary>
|
||||
[Obsolete("此配置已被弃用", true)]
|
||||
public static readonly DependencyProperty<bool> HandshakedProperty =
|
||||
DependencyProperty<bool>.Register("Handshaked", false);
|
||||
|
||||
/// <summary>
|
||||
/// 表示WebSocketVersion
|
||||
/// </summary>
|
||||
[Obsolete("此配置已被弃用", true)]
|
||||
public static readonly DependencyProperty<string> WebSocketVersionProperty =
|
||||
DependencyProperty<string>.Register("WebSocketVersion", "13");
|
||||
|
||||
/// <summary>
|
||||
/// 自动响应Close报文
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool> AutoCloseProperty =
|
||||
DependencyProperty<bool>.Register("AutoClose", true);
|
||||
|
||||
/// <summary>
|
||||
/// 自动响应Ping报文
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty<bool> AutoPongProperty =
|
||||
DependencyProperty<bool>.Register("AutoPong", false);
|
||||
|
||||
private IPluginManager m_pluginManager;
|
||||
|
||||
private string m_wSUrl = "/ws";
|
||||
@@ -83,45 +97,6 @@ namespace TouchSocket.Http.WebSockets
|
||||
return this;
|
||||
}
|
||||
|
||||
private async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (client.Protocol == Protocol.Http)
|
||||
{
|
||||
if (await this.VerifyConnection.Invoke(client, e.Context))
|
||||
{
|
||||
e.Handled = true;
|
||||
await client.SwitchProtocolToWebSocket(e.Context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
private async Task OnTcpDisconnected(ITcpClientBase client, DisconnectEventArgs e)
|
||||
{
|
||||
client.SetValue(HandshakedProperty, false);
|
||||
if (client.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
_ = internalWebSocket.TryInputReceiveAsync(null);
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
private async Task OnTcpReceived(ITcpClientBase client, ReceivedDataEventArgs e)
|
||||
{
|
||||
if (client.Protocol == Protocol.WebSocket)
|
||||
{
|
||||
if (e.RequestInfo is WSDataFrame dataFrame)
|
||||
{
|
||||
e.Handled = true;
|
||||
await this.OnHandleWSDataFrame(client, dataFrame);
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证连接
|
||||
/// </summary>
|
||||
@@ -175,35 +150,29 @@ namespace TouchSocket.Http.WebSockets
|
||||
{
|
||||
base.Loaded(pluginManager);
|
||||
this.m_pluginManager = pluginManager;
|
||||
pluginManager.Add<IHttpSocketClient, HttpContextEventArgs>(nameof(IHttpPlugin.OnHttpRequest),this.OnHttpRequest);
|
||||
|
||||
pluginManager.Add<ITcpClientBase, ReceivedDataEventArgs>(nameof(ITcpReceivedPlugin.OnTcpReceived),this.OnTcpReceived);
|
||||
|
||||
pluginManager.Add<ITcpClientBase, DisconnectEventArgs>(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected),this.OnTcpDisconnected);
|
||||
pluginManager.Add<IHttpSocketClient, HttpContextEventArgs>(nameof(IHttpPlugin.OnHttpRequest), this.OnHttpRequest);
|
||||
}
|
||||
|
||||
private async Task OnHandleWSDataFrame(ITcpClientBase client, WSDataFrame dataFrame)
|
||||
private async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
{
|
||||
if (this.AutoClose && dataFrame.IsClose)
|
||||
if (client.Protocol == Protocol.Http)
|
||||
{
|
||||
var msg = dataFrame.PayloadData?.ToString();
|
||||
await this.m_pluginManager.RaiseAsync(nameof(IWebSocketClosingPlugin.OnWebSocketClosing), client, new MsgPermitEventArgs() { Message = msg });
|
||||
client.Close(msg);
|
||||
return;
|
||||
}
|
||||
if (this.AutoPong && dataFrame.IsPing)
|
||||
{
|
||||
((HttpSocketClient)client).PongWS();
|
||||
return;
|
||||
}
|
||||
if (client.TryGetValue(WebSocketClientExtension.WebSocketProperty, out var internalWebSocket))
|
||||
{
|
||||
if (await internalWebSocket.TryInputReceiveAsync(dataFrame))
|
||||
if (await this.VerifyConnection.Invoke(client, e.Context))
|
||||
{
|
||||
e.Handled = true;
|
||||
await client.SwitchProtocolToWebSocket(e.Context);
|
||||
if (!this.AutoClose)
|
||||
{
|
||||
client.SetValue(AutoCloseProperty,false);
|
||||
}
|
||||
if (this.AutoPong)
|
||||
{
|
||||
client.SetValue(AutoPongProperty, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
await this.m_pluginManager.RaiseAsync(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), client, new WSDataFrameEventArgs(dataFrame));
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
private async Task<bool> ThisVerifyConnection(IHttpSocketClient client, HttpContext context)
|
||||
|
||||
@@ -20,10 +20,16 @@ namespace TouchSocket.Http.WebSockets
|
||||
/// 初始化一个适用于WebSocket的心跳插件
|
||||
/// </summary>
|
||||
[PluginOption(Singleton = true)]
|
||||
public class WebSocketHeartbeatPlugin : HeartbeatPlugin, IWebSocketHandshakedPlugin
|
||||
public class WebSocketHeartbeatPlugin : HeartbeatPlugin
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public Task OnWebSocketHandshaked(IHttpClientBase client, HttpContextEventArgs e)
|
||||
protected override void Loaded(IPluginManager pluginManager)
|
||||
{
|
||||
base.Loaded(pluginManager);
|
||||
pluginManager.Add<IWebSocket, HttpContextEventArgs>(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), OnWebSocketHandshaked);
|
||||
}
|
||||
|
||||
private Task OnWebSocketHandshaked(IWebSocket client, HttpContextEventArgs e)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
@@ -31,14 +37,14 @@ namespace TouchSocket.Http.WebSockets
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(this.Tick);
|
||||
if (!client.GetHandshaked())
|
||||
if (!client.IsHandshaked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
client.PingWS();
|
||||
client.Ping();
|
||||
failedCount = 0;
|
||||
}
|
||||
catch
|
||||
@@ -47,7 +53,7 @@ namespace TouchSocket.Http.WebSockets
|
||||
}
|
||||
if (failedCount > this.MaxFailCount)
|
||||
{
|
||||
client.CloseWithWS("自动心跳失败次数达到最大,已断开连接。");
|
||||
client.Close("自动心跳失败次数达到最大,已断开连接。");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace TouchSocket.JsonRpc
|
||||
|
||||
protected override void SendJsonString(string jsonString)
|
||||
{
|
||||
this.m_client.SendWithWS(jsonString);
|
||||
this.m_client.WebSocket.Send(jsonString);
|
||||
}
|
||||
|
||||
protected override Task SendJsonStringAsync(string jsonString)
|
||||
{
|
||||
return this.m_client.SendWithWSAsync(jsonString);
|
||||
return this.m_client.WebSocket.SendAsync(jsonString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Resources;
|
||||
using TouchSocket.Rpc;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于WebSocket协议的JsonRpc客户端。
|
||||
/// </summary>
|
||||
public class WebSocketJsonRpcClient : WebSocketClientBase, IWebSocketJsonRpcClient
|
||||
public class WebSocketJsonRpcClient : SetupClientWebSocket, IWebSocketJsonRpcClient
|
||||
{
|
||||
private readonly WaitHandlePool<JsonRpcWaitResult> m_waitHandle = new WaitHandlePool<JsonRpcWaitResult>();
|
||||
private IRpcServerProvider m_rpcServerProvider;
|
||||
@@ -37,6 +41,14 @@ namespace TouchSocket.JsonRpc
|
||||
/// </summary>
|
||||
public WaitHandlePool<JsonRpcWaitResult> WaitHandle => this.m_waitHandle;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsHandshaked => base.ProtectedIsHandshaked;
|
||||
|
||||
private ArraySegment<byte> GetInvokeBytes(JsonRpcRequest request)
|
||||
{
|
||||
return new ArraySegment<byte>(Encoding.UTF8.GetBytes(request.ToJsonString()));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Invoke(Type returnType, string method, IInvokeOption invokeOption, ref object[] parameters, Type[] types)
|
||||
{
|
||||
@@ -57,7 +69,7 @@ namespace TouchSocket.JsonRpc
|
||||
};
|
||||
try
|
||||
{
|
||||
this.SendWithWS(jsonRpcRequest.ToJsonString());
|
||||
this.Client.SendAsync(GetInvokeBytes(jsonRpcRequest), WebSocketMessageType.Text, true, CancellationToken.None).GetFalseAwaitResult();
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
@@ -131,7 +143,7 @@ namespace TouchSocket.JsonRpc
|
||||
};
|
||||
try
|
||||
{
|
||||
this.SendWithWS(jsonRpcRequest.ToJsonString());
|
||||
this.Client.SendAsync(GetInvokeBytes(jsonRpcRequest), WebSocketMessageType.Text, true, CancellationToken.None).GetFalseAwaitResult();
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
@@ -209,7 +221,7 @@ namespace TouchSocket.JsonRpc
|
||||
};
|
||||
try
|
||||
{
|
||||
await this.SendWithWSAsync(jsonRpcRequest.ToJsonString());
|
||||
await this.Client.SendAsync(GetInvokeBytes(jsonRpcRequest), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
@@ -275,7 +287,7 @@ namespace TouchSocket.JsonRpc
|
||||
};
|
||||
try
|
||||
{
|
||||
await this.SendWithWSAsync(jsonRpcRequest.ToJsonString());
|
||||
await this.Client.SendAsync(GetInvokeBytes(jsonRpcRequest), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
switch (invokeOption.FeedbackType)
|
||||
{
|
||||
case FeedbackType.OnlySend:
|
||||
@@ -341,39 +353,6 @@ namespace TouchSocket.JsonRpc
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task OnReceivedWSDataFrame(WSDataFrameEventArgs e)
|
||||
{
|
||||
var dataFrame = e.DataFrame;
|
||||
string jsonString = null;
|
||||
if (dataFrame.Opcode == WSDataType.Text)
|
||||
{
|
||||
jsonString = dataFrame.ToText();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(jsonString))
|
||||
{
|
||||
await base.OnReceivedWSDataFrame(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ActionMap.Count > 0 && JsonRpcUtility.IsJsonRpcRequest(jsonString))
|
||||
{
|
||||
_ = Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(this, jsonString));
|
||||
}
|
||||
else
|
||||
{
|
||||
var waitResult = JsonRpcUtility.ToJsonRpcWaitResult(jsonString);
|
||||
if (waitResult != null)
|
||||
{
|
||||
waitResult.Status = 1;
|
||||
this.m_waitHandle.SetRun(waitResult);
|
||||
}
|
||||
}
|
||||
|
||||
await base.OnReceivedWSDataFrame(e);
|
||||
}
|
||||
|
||||
private void RegisterServer(RpcMethod[] methodInstances)
|
||||
{
|
||||
foreach (var methodInstance in methodInstances)
|
||||
@@ -385,7 +364,7 @@ namespace TouchSocket.JsonRpc
|
||||
}
|
||||
}
|
||||
|
||||
private void Response(JsonRpcCallContextBase callContext, object result, JsonRpcError error)
|
||||
private async Task Response(JsonRpcCallContextBase callContext, object result, JsonRpcError error)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -407,21 +386,21 @@ namespace TouchSocket.JsonRpc
|
||||
};
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
this.SendWithWS(str);
|
||||
await this.Client.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(str)), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ThisInvoke(object obj)
|
||||
private async Task ThisInvoke(object obj)
|
||||
{
|
||||
var callContext = (JsonRpcCallContextBase)obj;
|
||||
var invokeResult = new InvokeResult();
|
||||
|
||||
try
|
||||
{
|
||||
JsonRpcUtility.BuildRequestContext(this.Resolver,this.ActionMap, ref callContext);
|
||||
JsonRpcUtility.BuildRequestContext(this.Resolver, this.ActionMap, ref callContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -451,7 +430,41 @@ namespace TouchSocket.JsonRpc
|
||||
return;
|
||||
}
|
||||
var error = JsonRpcUtility.GetJsonRpcError(invokeResult);
|
||||
this.Response(callContext, invokeResult.Result, error);
|
||||
await this.Response(callContext, invokeResult.Result, error);
|
||||
}
|
||||
|
||||
protected override void OnDisconnected(DisconnectEventArgs e)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override async Task OnReceived(System.Net.WebSockets.WebSocketReceiveResult result, ByteBlock byteBlock)
|
||||
{
|
||||
|
||||
if (result.MessageType != WebSocketMessageType.Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var jsonString = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
if (string.IsNullOrEmpty(jsonString))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.ActionMap.Count > 0 && JsonRpcUtility.IsJsonRpcRequest(jsonString))
|
||||
{
|
||||
_ = Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(this, jsonString));
|
||||
}
|
||||
else
|
||||
{
|
||||
var waitResult = JsonRpcUtility.ToJsonRpcWaitResult(jsonString);
|
||||
if (waitResult != null)
|
||||
{
|
||||
waitResult.Status = 1;
|
||||
this.m_waitHandle.SetRun(waitResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,16 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Sockets;
|
||||
|
||||
namespace TouchSocket.JsonRpc
|
||||
{
|
||||
/// <summary>
|
||||
/// IWebSocketJsonRpcClient
|
||||
/// </summary>
|
||||
public interface IWebSocketJsonRpcClient : IWebSocketClient, IJsonRpcClient
|
||||
public interface IWebSocketJsonRpcClient :ISetupConfigObject, IJsonRpcClient,IHandshakeObject,ICloseObject,IConnectObject
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -37,14 +37,14 @@ namespace TouchSocket.JsonRpc
|
||||
/// <summary>
|
||||
/// 经过判断是否标识当前的客户端为JsonRpc
|
||||
/// </summary>
|
||||
public Func<IHttpSocketClient, HttpContext, Task<bool>> AllowJsonRpc { get; set; }
|
||||
public Func<IWebSocket, HttpContext, Task<bool>> AllowJsonRpc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 经过判断是否标识当前的客户端为JsonRpc
|
||||
/// </summary>
|
||||
/// <param name="allowJsonRpc"></param>
|
||||
/// <returns></returns>
|
||||
public WebSocketJsonRpcParserPlugin SetAllowJsonRpc(Func<IHttpSocketClient, HttpContext, Task<bool>> allowJsonRpc)
|
||||
public WebSocketJsonRpcParserPlugin SetAllowJsonRpc(Func<IWebSocket, HttpContext, Task<bool>> allowJsonRpc)
|
||||
{
|
||||
this.AllowJsonRpc = allowJsonRpc;
|
||||
return this;
|
||||
@@ -55,7 +55,7 @@ namespace TouchSocket.JsonRpc
|
||||
/// </summary>
|
||||
/// <param name="allowJsonRpc"></param>
|
||||
/// <returns></returns>
|
||||
public WebSocketJsonRpcParserPlugin SetAllowJsonRpc(Func<IHttpSocketClient, HttpContext, bool> allowJsonRpc)
|
||||
public WebSocketJsonRpcParserPlugin SetAllowJsonRpc(Func<IWebSocket, HttpContext, bool> allowJsonRpc)
|
||||
{
|
||||
this.AllowJsonRpc = (client, context) =>
|
||||
{
|
||||
@@ -68,9 +68,9 @@ namespace TouchSocket.JsonRpc
|
||||
protected override void Loaded(IPluginManager pluginManager)
|
||||
{
|
||||
base.Loaded(pluginManager);
|
||||
pluginManager.Add<IHttpSocketClient, HttpContextEventArgs>(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this.OnWebSocketHandshaked);
|
||||
pluginManager.Add<IWebSocket, HttpContextEventArgs>(nameof(IWebSocketHandshakedPlugin.OnWebSocketHandshaked), this.OnWebSocketHandshaked);
|
||||
|
||||
pluginManager.Add<IHttpSocketClient, WSDataFrameEventArgs>(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this.OnWebSocketReceived);
|
||||
pluginManager.Add<IWebSocket, WSDataFrameEventArgs>(nameof(IWebSocketReceivedPlugin.OnWebSocketReceived), this.OnWebSocketReceived);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -96,53 +96,53 @@ namespace TouchSocket.JsonRpc
|
||||
};
|
||||
}
|
||||
var str = JsonRpcUtility.ToJsonRpcResponseString(response);
|
||||
((IHttpSocketClient)callContext.Caller).SendWithWS(str);
|
||||
((IHttpSocketClient)callContext.Caller).WebSocket.Send(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnWebSocketHandshaked(IHttpSocketClient client, HttpContextEventArgs e)
|
||||
private async Task OnWebSocketHandshaked(IWebSocket client, HttpContextEventArgs e)
|
||||
{
|
||||
if (this.AllowJsonRpc != null)
|
||||
{
|
||||
if (await this.AllowJsonRpc.Invoke(client, e.Context))
|
||||
{
|
||||
client.SetIsJsonRpc();
|
||||
client.Client.SetIsJsonRpc();
|
||||
}
|
||||
}
|
||||
|
||||
await e.InvokeNext();
|
||||
}
|
||||
|
||||
private Task OnWebSocketReceived(IHttpSocketClient client, WSDataFrameEventArgs e)
|
||||
private async Task OnWebSocketReceived(IWebSocket client, WSDataFrameEventArgs e)
|
||||
{
|
||||
if (e.DataFrame.Opcode == WSDataType.Text && client.GetIsJsonRpc())
|
||||
if (e.DataFrame.Opcode == WSDataType.Text && client.Client.GetIsJsonRpc())
|
||||
{
|
||||
var jsonRpcStr = e.DataFrame.ToText();
|
||||
if (jsonRpcStr.IsNullOrEmpty())
|
||||
{
|
||||
return e.InvokeNext();
|
||||
await e.InvokeNext();
|
||||
return;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
|
||||
if (client.TryGetValue(JsonRpcClientExtension.JsonRpcActionClientProperty, out var actionClient)
|
||||
if (client.Client.TryGetValue(JsonRpcClientExtension.JsonRpcActionClientProperty, out var actionClient)
|
||||
&& !JsonRpcUtility.IsJsonRpcRequest(jsonRpcStr))
|
||||
{
|
||||
actionClient.InputResponseString(jsonRpcStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(client, jsonRpcStr));
|
||||
_=Task.Factory.StartNew(this.ThisInvoke, new WebSocketJsonRpcCallContext(client.Client, jsonRpcStr));
|
||||
}
|
||||
|
||||
return EasyTask.CompletedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return e.InvokeNext();
|
||||
await e.InvokeNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>JsonRpc;TouchSocket</PackageTags>
|
||||
<Description>这是一个提供JsonRpc服务器和客户端的组件库。可以通过该组件创建基于Tcp、Http、WebSocket协议的JsonRpc服务器和客户端,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Modbus;Master;TouchSocket</PackageTags>
|
||||
<Description>这是一个Modbus功能库,目前包括ModbusTcpMaster、ModbusUdpMaster、ModbusRtuMaster、ModbusRtuOverTcpMaster、ModbusRtuOverUdpMaster。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Pipeline;NamedPipe;Ipc;TouchSocket</PackageTags>
|
||||
<Description>这是一个基于命名管道的组件库。它模仿Tcp封装了命名管道的服务器和客户端,以及连接、断开连接等消息。功能上实现了多管道名称监听、流式数据解析,以极致接近Tcp的体验使用命名管道。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Rpc;RateLimiting;TouchSocket</PackageTags>
|
||||
<Description>这是一个扩展于Rpc管理平台的限流包。目前支持开发DmtpRpc、XmlRpc、JsonRpc、WebApi等所有Rpc部分。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Rpc;TouchSocket</PackageTags>
|
||||
<Description>这是一个超轻量、高性能、可扩展的Rpc管理平台框架。您可以基于该框架,快速开发出Rpc执行。目前已扩展开发DmtpRpc、XmlRpc、JsonRpc、WebApi部分。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Serial;SerialPort;TouchSocket</PackageTags>
|
||||
<Description>这是.Net(包括 C# 、VB.Net、F#)的一个整合性的串口通信框架。包含了串口连接、断开等一系列的通信事务。同时能一键式解决数据黏分包问题。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Swagger;TouchSocket</PackageTags>
|
||||
<Description>这是适用于TouchSocket.WebApi的Swagger页面,可以直接在浏览器调试WebApi。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>WebApi;TouchSocket</PackageTags>
|
||||
<Description>这是一个提供WebApi服务器和客户端的组件库。可以通过该组件创建WebApi服务解析器和客户端,让桌面端、Web端、移动端可以跨语言调用Rpc函数。功能支持自定义路由、Get传参、Post传参等。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>XmlRpc;TouchSocket</PackageTags>
|
||||
<Description>这是一个提供XmlRpc服务器和客户端的组件库。可以通过该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,Array等。也能与CookComputing.XmlRpcV2完美对接。不限Web,Android等平台。
|
||||
|
||||
|
||||
@@ -92,87 +92,5 @@ namespace TouchSocket.Sockets
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region 连接
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.Connect(int, System.Threading.CancellationToken)"/>
|
||||
public static TClient Connect<TClient>(this TClient client, IPHost ipHost, int millisecondsTimeout = 5000) where TClient : ITcpClient
|
||||
{
|
||||
TouchSocketConfig config;
|
||||
if (client.Config == null)
|
||||
{
|
||||
config = new TouchSocketConfig();
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
client.Setup(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = client.Config;
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
}
|
||||
client.Connect(millisecondsTimeout);
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.ConnectAsync(int, System.Threading.CancellationToken)"/>
|
||||
public static async Task<TClient> ConnectAsync<TClient>(this TClient client, IPHost ipHost, int millisecondsTimeout = 5000) where TClient : ITcpClient
|
||||
{
|
||||
TouchSocketConfig config;
|
||||
if (client.Config == null)
|
||||
{
|
||||
config = new TouchSocketConfig();
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
await client.SetupAsync(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = client.Config;
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
}
|
||||
await client.ConnectAsync(millisecondsTimeout);
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <returns></returns>
|
||||
public static Result TryConnect<TClient>(this TClient client, int millisecondsTimeout = 5000) where TClient : ITcpClient
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Connect(millisecondsTimeout);
|
||||
return new Result(ResultCode.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Result> TryConnectAsync<TClient>(this TClient client, int millisecondsTimeout = 5000) where TClient : ITcpClient
|
||||
{
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(millisecondsTimeout);
|
||||
return new Result(ResultCode.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 连接
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
@@ -74,5 +76,65 @@ namespace TouchSocket.Sockets
|
||||
{
|
||||
SafeClose(client, "SafeClose");
|
||||
}
|
||||
|
||||
//#region CloseAsync
|
||||
///// <summary>
|
||||
///// <inheritdoc cref="ICloseObject.CloseAsync(string)"/>
|
||||
///// </summary>
|
||||
///// <typeparam name="T"></typeparam>
|
||||
///// <param name="client"></param>
|
||||
//public static Task CloseAsync<T>(this T client) where T : ICloseObject
|
||||
//{
|
||||
// return client.CloseAsync(string.Empty);
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// <inheritdoc cref="ICloseObject.CloseAsync(string)"/>
|
||||
///// </summary>
|
||||
///// <typeparam name="T"></typeparam>
|
||||
///// <param name="client"></param>
|
||||
///// <param name="msg"></param>
|
||||
//public static async Task SafeCloseAsync<T>(this T client, string msg) where T : ICloseObject
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// if (client == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// if (client is IOnlineClient onlineClient)
|
||||
// {
|
||||
// if (onlineClient.Online)
|
||||
// {
|
||||
// await client.CloseAsync(msg);
|
||||
// }
|
||||
// }
|
||||
// else if (client is IHandshakeObject handshakeObject)
|
||||
// {
|
||||
// if (handshakeObject.IsHandshaked)
|
||||
// {
|
||||
// await client.CloseAsync(msg);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// await client.CloseAsync(msg);
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// <inheritdoc cref="ICloseObject.CloseAsync(string)"/>
|
||||
///// </summary>
|
||||
///// <typeparam name="T"></typeparam>
|
||||
///// <param name="client"></param>
|
||||
//public static Task SafeCloseAsync<T>(this T client) where T : ICloseObject
|
||||
//{
|
||||
// return SafeCloseAsync(client, "SafeClose");
|
||||
//}
|
||||
//#endregion
|
||||
}
|
||||
}
|
||||
@@ -22,20 +22,56 @@ namespace TouchSocket.Sockets
|
||||
/// </summary>
|
||||
public static class ConnectObjectExtension
|
||||
{
|
||||
#region 连接
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.Connect(int, CancellationToken)"/>
|
||||
public static void Connect(this IConnectObject client, int millisecondsTimeout = 5000)
|
||||
{
|
||||
client.Connect(millisecondsTimeout, CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.Connect(int, System.Threading.CancellationToken)"/>
|
||||
public static TClient Connect<TClient>(this TClient client, IPHost ipHost, int millisecondsTimeout = 5000) where TClient : ISetupConfigObject, IConnectObject
|
||||
{
|
||||
TouchSocketConfig config;
|
||||
if (client.Config == null)
|
||||
{
|
||||
config = new TouchSocketConfig();
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
client.Setup(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = client.Config;
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
}
|
||||
client.Connect(millisecondsTimeout);
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.ConnectAsync(int, CancellationToken)"/>
|
||||
public static async Task ConnectAsync(this IConnectObject client, int millisecondsTimeout = 5000)
|
||||
{
|
||||
await client.ConnectAsync(millisecondsTimeout, CancellationToken.None);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IConnectObject.ConnectAsync(int, System.Threading.CancellationToken)"/>
|
||||
public static async Task<TClient> ConnectAsync<TClient>(this TClient client, IPHost ipHost, int millisecondsTimeout = 5000) where TClient : ISetupConfigObject, IConnectObject
|
||||
{
|
||||
TouchSocketConfig config;
|
||||
if (client.Config == null)
|
||||
{
|
||||
config = new TouchSocketConfig();
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
await client.SetupAsync(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
config = client.Config;
|
||||
config.SetRemoteIPHost(ipHost);
|
||||
}
|
||||
await client.ConnectAsync(millisecondsTimeout);
|
||||
return client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
@@ -55,6 +91,26 @@ namespace TouchSocket.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <returns></returns>
|
||||
public static Result TryConnect<TClient>(this TClient client, int millisecondsTimeout = 5000) where TClient : ISetupConfigObject, IConnectObject
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Connect(millisecondsTimeout);
|
||||
return new Result(ResultCode.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
@@ -74,6 +130,24 @@ namespace TouchSocket.Sockets
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 连接
|
||||
/// <summary>
|
||||
/// 尝试连接。不会抛出异常。
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="millisecondsTimeout"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Result> TryConnectAsync<TClient>(this TClient client, int millisecondsTimeout = 5000) where TClient : ISetupConfigObject, IConnectObject
|
||||
{
|
||||
try
|
||||
{
|
||||
await client.ConnectAsync(millisecondsTimeout);
|
||||
return new Result(ResultCode.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result(ResultCode.Exception, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Authentication;
|
||||
using TouchSocket.Core;
|
||||
|
||||
@@ -505,12 +506,12 @@ namespace TouchSocket.Sockets
|
||||
#region 创建
|
||||
|
||||
/// <summary>
|
||||
/// 构建Tcp类客户端,并连接
|
||||
/// 构建可配置,可连接类客户端,并连接
|
||||
/// </summary>
|
||||
/// <typeparam name="TClient"></typeparam>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
public static TClient BuildClient<TClient>(this TouchSocketConfig config) where TClient : ITcpClient, new()
|
||||
public static TClient BuildClient<TClient>(this TouchSocketConfig config) where TClient : ISetupConfigObject,IConnectObject, new()
|
||||
{
|
||||
var client = new TClient();
|
||||
client.Setup(config);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TouchSocket.Sockets
|
||||
{
|
||||
@@ -23,7 +24,13 @@ namespace TouchSocket.Sockets
|
||||
/// 关闭客户端。
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <exception cref="Exception"></exception>
|
||||
void Close(string msg);
|
||||
|
||||
///// <summary>
|
||||
///// 异步关闭客户端。
|
||||
///// </summary>
|
||||
///// <param name="msg"></param>
|
||||
///// <returns></returns>
|
||||
//Task CloseAsync(string msg);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace TouchSocket.Sockets
|
||||
/// <summary>
|
||||
/// Tcp客户端终端接口
|
||||
/// </summary>
|
||||
public interface ITcpClient : ITcpClientBase, IClientSender, IPluginObject, ISetupConfigObject, IConnectObject
|
||||
public interface ITcpClient : ITcpClientBase, IClientSender, ISetupConfigObject, IConnectObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 成功连接到服务器
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<PackageTags>Tcp;Udp;Ssl;Socket;Saea;TouchSocket</PackageTags>
|
||||
<Description>TouchSocket是.Net(包括 C# 、VB.Net、F#)的一个整合性的socket网络通信框架。包含了 tcp、udp、ssl等一系列的通信模块。一键式解决 tcp 黏分包问题,udp大数据包分片组合问题等。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user