mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-08 02:39:29 +08:00
clean file useless
This commit is contained in:
parent
3e6a3bbc2a
commit
ff32f44223
244
FastTunnel.Core/Client/FastTunnelClient - Copy.cs
Normal file
244
FastTunnel.Core/Client/FastTunnelClient - Copy.cs
Normal file
|
@ -0,0 +1,244 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Models;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using System.Timers;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using FastTunnel.Core.Handlers.Client;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using FastTunnel.Core.Server;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text.Json;
|
||||
using FastTunnel.Core.Protocol;
|
||||
|
||||
namespace FastTunnel.Core.Client
|
||||
{
|
||||
public class FastTunnelClient : IFastTunnelClient
|
||||
{
|
||||
//Socket _client;
|
||||
private IFastTunnelClientSocket socket;
|
||||
|
||||
protected ILogger<FastTunnelClient> _logger;
|
||||
|
||||
System.Timers.Timer timer_heart;
|
||||
|
||||
double heartInterval = 10 * 1000; // 10 秒心跳
|
||||
public DateTime lastHeart;
|
||||
|
||||
int reTrySpan = 10 * 1000; // 登陆失败后重试间隔
|
||||
HttpRequestHandler _newCustomerHandler;
|
||||
NewForwardHandler _newSSHHandler;
|
||||
LogHandler _logHandler;
|
||||
ClientHeartHandler _clientHeartHandler;
|
||||
Message<LogInMassage> loginMsg;
|
||||
protected readonly IOptionsMonitor<DefaultClientConfig> _configuration;
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
|
||||
public SuiDaoServer Server { get; protected set; }
|
||||
|
||||
public FastTunnelClient(
|
||||
ILogger<FastTunnelClient> logger,
|
||||
HttpRequestHandler newCustomerHandler,
|
||||
NewForwardHandler newSSHHandler, LogHandler logHandler,
|
||||
IOptionsMonitor<DefaultClientConfig> configuration,
|
||||
ClientHeartHandler clientHeartHandler)
|
||||
{
|
||||
_logger = logger;
|
||||
_newCustomerHandler = newCustomerHandler;
|
||||
_newSSHHandler = newSSHHandler;
|
||||
_logHandler = logHandler;
|
||||
_clientHeartHandler = clientHeartHandler;
|
||||
_configuration = configuration;
|
||||
|
||||
timer_heart = new System.Timers.Timer();
|
||||
timer_heart.AutoReset = false;
|
||||
timer_heart.Interval = heartInterval;
|
||||
timer_heart.Elapsed += HeartElapsed;
|
||||
}
|
||||
|
||||
private async Task reConnAsync()
|
||||
{
|
||||
Close();
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.Sleep(reTrySpan);
|
||||
|
||||
_logger.LogInformation("登录重试...");
|
||||
socket = await loginAsync(CancellationToken.None);
|
||||
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
}
|
||||
} while (true);
|
||||
|
||||
await connSuccessAsync();
|
||||
}
|
||||
|
||||
private async void HeartElapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
timer_heart.Enabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
socket.SendAsync(new Message<HeartMassage> { MessageType = MessageType.Heart, Content = null }, cancellationTokenSource.Token).Wait();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 与服务端断开连接
|
||||
await reConnAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
timer_heart.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动客户端
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="customLoginMsg">自定义登录信息,可进行扩展业务</param>
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.cancellationTokenSource.Token);
|
||||
|
||||
_logger.LogInformation("===== FastTunnel Client Start =====");
|
||||
|
||||
try
|
||||
{
|
||||
socket = await loginAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
|
||||
await reConnAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
_ = connSuccessAsync();
|
||||
}
|
||||
|
||||
protected virtual async Task<IFastTunnelClientSocket> loginAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Server = _configuration.CurrentValue.Server;
|
||||
_logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
|
||||
|
||||
try
|
||||
{
|
||||
// 连接到的目标IP
|
||||
socket = new DefultClientSocket();
|
||||
|
||||
await socket.ConnectAsync(
|
||||
new Uri($"ws://{_configuration.CurrentValue.Server.ServerAddr}:{_configuration.CurrentValue.Server.ServerPort}"), cancellationToken);
|
||||
|
||||
_logger.LogInformation("连接成功");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
loginMsg = new Message<LogInMassage>
|
||||
{
|
||||
MessageType = MessageType.C_LogIn,
|
||||
Content = new LogInMassage
|
||||
{
|
||||
Webs = _configuration.CurrentValue.Webs,
|
||||
SSH = _configuration.CurrentValue.Forwards,
|
||||
},
|
||||
};
|
||||
|
||||
// 登录
|
||||
await socket.SendAsync(loginMsg, cancellationToken);
|
||||
return socket;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
timer_heart.Stop();
|
||||
socket.CloseAsync();
|
||||
}
|
||||
|
||||
private async Task connSuccessAsync()
|
||||
{
|
||||
_logger.LogDebug("通信已建立");
|
||||
|
||||
// 心跳开始
|
||||
timer_heart.Start();
|
||||
|
||||
await ReceiveServerAsync(socket);
|
||||
// await new PipeHepler(_client, ProceccLine).ProcessLinesAsync();
|
||||
}
|
||||
|
||||
private async Task ReceiveServerAsync(IFastTunnelClientSocket client)
|
||||
{
|
||||
var tunnelProtocol = new TunnelProtocol();
|
||||
byte[] buffer = new byte[512];
|
||||
int n = 0;
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
n = await client.ReceiveAsync(buffer, cancellationTokenSource.Token);
|
||||
var cmds = tunnelProtocol.HandleBuffer(buffer, 0, n);
|
||||
|
||||
foreach (var item in cmds)
|
||||
{
|
||||
await HandleServerRequestAsync(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleServerRequestAsync(string lineCmd)
|
||||
{
|
||||
_logger.LogInformation($"服务端指令 {lineCmd}");
|
||||
var cmds = lineCmd.Split("||");
|
||||
var type = cmds[0];
|
||||
|
||||
TunnelMassage msg = null;
|
||||
IClientHandler handler;
|
||||
switch (type)
|
||||
{
|
||||
case "Heart":
|
||||
handler = _clientHeartHandler;
|
||||
break;
|
||||
case "S_NewCustomer":
|
||||
handler = _newCustomerHandler;
|
||||
msg = JsonSerializer.Deserialize<NewCustomerMassage>(cmds[1]);
|
||||
break;
|
||||
case "S_NewSSH":
|
||||
handler = _newSSHHandler;
|
||||
msg = JsonSerializer.Deserialize<NewForwardMessage>(cmds[1]);
|
||||
break;
|
||||
case "Log":
|
||||
handler = _logHandler;
|
||||
msg = JsonSerializer.Deserialize<LogMassage>(cmds[1]);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"未处理的消息:{lineCmd}");
|
||||
}
|
||||
|
||||
await handler.HandlerMsgAsync(this, msg);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ using System.Threading;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using FastTunnel.Core.Handlers.Client;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using FastTunnel.Core.Server;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Net.WebSockets;
|
||||
|
@ -21,11 +20,8 @@ namespace FastTunnel.Core.Client
|
|||
{
|
||||
public class FastTunnelClient : IFastTunnelClient
|
||||
{
|
||||
//Socket _client;
|
||||
private IFastTunnelClientSocket socket;
|
||||
|
||||
protected ILogger<FastTunnelClient> _logger;
|
||||
|
||||
public DateTime lastHeart;
|
||||
|
||||
HttpRequestHandler _newCustomerHandler;
|
||||
|
@ -63,17 +59,8 @@ namespace FastTunnel.Core.Client
|
|||
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.cancellationTokenSource.Token);
|
||||
|
||||
_logger.LogInformation("===== FastTunnel Client Start =====");
|
||||
|
||||
try
|
||||
{
|
||||
socket = await loginAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
socket = await loginAsync(cancellationToken);
|
||||
_logger.LogInformation($"通讯已建立");
|
||||
await ReceiveServerAsync(socket);
|
||||
}
|
||||
|
||||
|
@ -144,10 +131,6 @@ namespace FastTunnel.Core.Client
|
|||
IClientHandler handler;
|
||||
switch (type)
|
||||
{
|
||||
case "Heart":
|
||||
handler = _clientHeartHandler;
|
||||
msg = JsonSerializer.Deserialize<HeartMassage>(cmds[1]);
|
||||
break;
|
||||
case "S_NewCustomer":
|
||||
handler = _newCustomerHandler;
|
||||
msg = JsonSerializer.Deserialize<NewCustomerMassage>(cmds[1]);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using System.Collections.Concurrent;
|
||||
using System;
|
||||
using FastTunnel.Core.Listener;
|
||||
|
@ -18,8 +17,6 @@ namespace FastTunnel.Core.Client
|
|||
{
|
||||
public class FastTunnelServer
|
||||
{
|
||||
public ConcurrentDictionary<string, NewRequest> RequestTemp { get; private set; } = new ConcurrentDictionary<string, NewRequest>();
|
||||
|
||||
public ConcurrentDictionary<string, TaskCompletionSource<Stream>> ResponseTasks { get; } = new();
|
||||
|
||||
public ConcurrentDictionary<string, WebInfo> WebList { get; private set; } = new();
|
||||
|
@ -28,8 +25,6 @@ namespace FastTunnel.Core.Client
|
|||
= new ConcurrentDictionary<int, ForwardInfo<ForwardHandlerArg>>();
|
||||
|
||||
readonly ILogger _logger;
|
||||
//readonly ClientListenerV2 clientListener;
|
||||
//readonly HttpListenerV2 http_listener;
|
||||
public readonly IOptionsMonitor<DefaultServerConfig> serverOption;
|
||||
public IProxyConfigProvider proxyConfig;
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ namespace FastTunnel.Core.Config
|
|||
{
|
||||
public interface IServerConfig
|
||||
{
|
||||
// int BindPort { get; set; }
|
||||
|
||||
#region Web相关配置
|
||||
|
||||
int WebProxyPort { get; set; }
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Handlers;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using FastTunnel.Core.Models;
|
||||
using FastTunnel.Core.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Dispatchers
|
||||
{
|
||||
public class ClientDispatcher : IListenerDispatcher
|
||||
{
|
||||
readonly ILogger _logger;
|
||||
readonly IServerConfig _serverSettings;
|
||||
readonly FastTunnelServer _fastTunnelServer;
|
||||
|
||||
readonly LoginHandler _loginHandler;
|
||||
readonly HeartMessageHandler _heartHandler;
|
||||
readonly SwapMessageHandler _swapMsgHandler;
|
||||
Action<Socket> offLineAction;
|
||||
|
||||
public ClientDispatcher(FastTunnelServer fastTunnelServer, ILogger logger, IServerConfig serverSettings)
|
||||
{
|
||||
_logger = logger;
|
||||
_serverSettings = serverSettings;
|
||||
_fastTunnelServer = fastTunnelServer;
|
||||
|
||||
_loginHandler = new LoginHandler(logger);
|
||||
_heartHandler = new HeartMessageHandler();
|
||||
_swapMsgHandler = new SwapMessageHandler(logger);
|
||||
}
|
||||
|
||||
string temp = string.Empty;
|
||||
|
||||
public void Dispatch(Socket client)
|
||||
{
|
||||
var reader = new DataReciver(client);
|
||||
reader.OnComplete += Reader_OnComplete;
|
||||
reader.OnError += Reader_OnError;
|
||||
reader.OnReset += Reader_OnReset;
|
||||
reader.ReciveOneAsync();
|
||||
}
|
||||
|
||||
private void Reader_OnReset(DataReciver send, Socket socket, SocketAsyncEventArgs e)
|
||||
{
|
||||
offLineAction(socket);
|
||||
}
|
||||
|
||||
private void Reader_OnError(DataReciver send, SocketAsyncEventArgs e)
|
||||
{
|
||||
_logger.LogError("接收客户端数据异常 {0}", e.SocketError);
|
||||
}
|
||||
|
||||
private void Reader_OnComplete(DataReciver reader, byte[] buffer, int offset, int count)
|
||||
{
|
||||
var words = Encoding.UTF8.GetString(buffer, offset, count);
|
||||
words += temp;
|
||||
temp = string.Empty;
|
||||
|
||||
_logger.LogDebug($"revice from client: {words}");
|
||||
|
||||
try
|
||||
{
|
||||
int index = 0;
|
||||
bool needRecive = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var firstIndex = words.IndexOf("\n");
|
||||
if (firstIndex < 0)
|
||||
{
|
||||
temp += words;
|
||||
reader.ReciveOneAsync();
|
||||
break;
|
||||
}
|
||||
|
||||
var sub_words = words.Substring(index, firstIndex + 1);
|
||||
var res = handle(sub_words, reader.Socket);
|
||||
|
||||
if (res.NeedRecive)
|
||||
needRecive = true;
|
||||
|
||||
words = words.Replace(sub_words, string.Empty);
|
||||
if (string.IsNullOrEmpty(words))
|
||||
break;
|
||||
}
|
||||
|
||||
if (needRecive)
|
||||
{
|
||||
reader.ReciveOneAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
_logger.LogError($"handle fail msg:{words}");
|
||||
|
||||
// throw;
|
||||
reader.Socket.Send(new Message<LogMassage>() { MessageType = MessageType.Log, Content = new LogMassage(LogMsgType.Error, ex.Message) });
|
||||
reader.ReciveOneAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private IClientMessageHandler handle(string words, Socket client)
|
||||
{
|
||||
Message<JObject> msg = JsonConvert.DeserializeObject<Message<JObject>>(words);
|
||||
|
||||
|
||||
IClientMessageHandler handler = null;
|
||||
switch (msg.MessageType)
|
||||
{
|
||||
case MessageType.C_LogIn: // 登录
|
||||
handler = _loginHandler;
|
||||
break;
|
||||
case MessageType.Heart: // 心跳
|
||||
handler = _heartHandler;
|
||||
break;
|
||||
case MessageType.C_SwapMsg: // 交换数据
|
||||
handler = _swapMsgHandler;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"未知的通讯指令 {msg.MessageType}");
|
||||
}
|
||||
|
||||
handler.HandlerMsg(this._fastTunnelServer, client, msg);
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void Dispatch(Socket httpClient, Action<Socket> onOffLine)
|
||||
{
|
||||
offLineAction = onOffLine;
|
||||
Dispatch(httpClient);
|
||||
}
|
||||
|
||||
public void Dispatch(AsyncUserToken token, string words)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Http;
|
||||
using System.IO;
|
||||
using FastTunnel.Core.Server;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace FastTunnel.Core.Dispatchers
|
||||
{
|
||||
public class HttpDispatcherV2 : IListenerDispatcher
|
||||
{
|
||||
readonly ILogger _logger;
|
||||
readonly IOptionsMonitor<DefaultServerConfig> _serverOption;
|
||||
readonly FastTunnelServer _fastTunnelServer;
|
||||
|
||||
public HttpDispatcherV2(FastTunnelServer fastTunnelServer, ILogger logger, IOptionsMonitor<DefaultServerConfig> serverSettings)
|
||||
{
|
||||
_logger = logger;
|
||||
_serverOption = serverSettings;
|
||||
_fastTunnelServer = fastTunnelServer;
|
||||
}
|
||||
|
||||
static string pattern = @"[hH]ost:.+";
|
||||
|
||||
public void Dispatch(AsyncUserToken token, string words)
|
||||
{
|
||||
_logger.LogDebug($"=======Dispatch HTTP {token.RequestId}========");
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
// 1.检查白名单
|
||||
try
|
||||
{
|
||||
var endpoint = token.Socket.RemoteEndPoint as System.Net.IPEndPoint;
|
||||
_logger.LogInformation($"Receive HTTP Request {endpoint.Address}:{endpoint.Port}");
|
||||
|
||||
if (_serverOption.CurrentValue.WebAllowAccessIps != null)
|
||||
{
|
||||
if (!_serverOption.CurrentValue.WebAllowAccessIps.Contains(endpoint.Address.ToString()))
|
||||
{
|
||||
HandlerHostNotAccess(token.Socket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
}
|
||||
|
||||
string Host;
|
||||
MatchCollection collection = Regex.Matches(words, pattern);
|
||||
if (collection.Count == 0)
|
||||
{
|
||||
_logger.LogError($"【Host异常】:{words}");
|
||||
|
||||
// 返回错误页
|
||||
HandlerHostRequired(token.Socket);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Host = collection[0].Value;
|
||||
}
|
||||
|
||||
var domain = Host.Split(":")[1].Trim();
|
||||
|
||||
_logger.LogDebug($"=======Dispatch domain:{domain} {token.RequestId} ========");
|
||||
|
||||
// 判断是否为ip
|
||||
if (IsIpDomian(domain))
|
||||
{
|
||||
// 返回错误页
|
||||
HandlerHostRequired(token.Socket);
|
||||
return;
|
||||
}
|
||||
|
||||
WebInfo web;
|
||||
if (!_fastTunnelServer.WebList.TryGetValue(domain, out web))
|
||||
{
|
||||
_logger.LogDebug($"=======站点未登录 {token.RequestId}========");
|
||||
HandlerClientNotOnLine(token.Socket, domain);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 发送指令给客户端,等待建立隧道
|
||||
web.Socket.SendCmd(new Message<NewCustomerMassage> { MessageType = MessageType.S_NewCustomer, Content = new NewCustomerMassage { MsgId = token.RequestId, WebConfig = web.WebConfig } });
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.LogDebug($"[客户端不在线] {token.RequestId}");
|
||||
HandlerClientNotOnLine(token.Socket, domain);
|
||||
|
||||
// 移除
|
||||
_fastTunnelServer.WebList.TryRemove(domain, out _);
|
||||
}
|
||||
|
||||
// 将等待的http请求
|
||||
_fastTunnelServer.RequestTemp.TryAdd(token.RequestId, new NewRequest
|
||||
{
|
||||
CustomerClient = token.Socket,
|
||||
Buffer = token.Recived
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispatch(Socket httpClient)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private bool IsIpDomian(string domain)
|
||||
{
|
||||
return Regex.IsMatch(domain, @"^\d.\d.\d.\d.\d$");
|
||||
}
|
||||
|
||||
private void HandlerHostNotAccess(Socket client)
|
||||
{
|
||||
_logger.LogDebug($"### NotAccessIps:'{client.RemoteEndPoint}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NotAccessIps);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void HandlerHostRequired(Socket client)
|
||||
{
|
||||
_logger.LogDebug($"### HostRequired:'{client.RemoteEndPoint}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_HostRequired);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void HandlerClientNotOnLine(Socket client, string domain)
|
||||
{
|
||||
_logger.LogDebug($"### TunnelNotFound:'{domain}'");
|
||||
string statusLine = "HTTP/1.1 200 OK\r\n";
|
||||
string responseHeader = "Content-Type: text/html\r\n";
|
||||
|
||||
byte[] responseBody = Encoding.UTF8.GetBytes(TunnelResource.Page_NoTunnel);
|
||||
|
||||
client.Send(Encoding.UTF8.GetBytes(statusLine));
|
||||
client.Send(Encoding.UTF8.GetBytes(responseHeader));
|
||||
client.Send(Encoding.UTF8.GetBytes("\r\n"));
|
||||
client.Send(responseBody);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
public void Dispatch(Socket httpClient, Action<Socket> onOffLine)
|
||||
{
|
||||
Dispatch(httpClient);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using FastTunnel.Core.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Dispatchers
|
||||
{
|
||||
public interface IListenerDispatcher
|
||||
{
|
||||
void Dispatch(AsyncUserToken token, string words);
|
||||
|
||||
void DispatchAsync(Socket httpClient);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FastTunnel.Core.Extensions
|
||||
{
|
||||
public static class ByteArrayExtension
|
||||
public static class ByteArrayExtensions
|
||||
{
|
||||
public static string GetString(this byte[] buffer, int offset, int count)
|
||||
{
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Extensions
|
||||
{
|
||||
public static class LogExtentions
|
||||
public static class LoggerExtentions
|
||||
{
|
||||
public static void LogError(this ILogger logger, Exception ex)
|
||||
{
|
|
@ -6,7 +6,7 @@ using System.Text;
|
|||
|
||||
namespace FastTunnel.Core.Extensions
|
||||
{
|
||||
public static class SocketExtension
|
||||
public static class SocketExtensions
|
||||
{
|
||||
public static void SendCmd<T>(this Socket socket, Message<T> message)
|
||||
where T : TunnelMassage
|
|
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FastTunnel.Core.Extensions
|
||||
{
|
||||
public static class WebSocketExtension
|
||||
public static class WebSocketExtensions
|
||||
{
|
||||
public static async Task SendCmdAsync<T>(this WebSocket socket, Message<T> message,
|
||||
WebSocketMessageType webSocketMessage, bool end, CancellationToken cancellationToken)
|
|
@ -26,9 +26,6 @@
|
|||
<Compile Remove="Client\SuiDaoServer.cs.BASE.cs" />
|
||||
<Compile Remove="Client\SuiDaoServer.cs.LOCAL.cs" />
|
||||
<Compile Remove="Client\SuiDaoServer.cs.REMOTE.cs" />
|
||||
<Compile Remove="Dispatchers\ClientDispatcher.cs" />
|
||||
<Compile Remove="Dispatchers\HttpDispatcher.cs" />
|
||||
<Compile Remove="Dispatchers\HttpDispatcherV2.cs" />
|
||||
<Compile Remove="Handlers\Server\SwapMessageHandler.cs" />
|
||||
<Compile Remove="Listener.cs" />
|
||||
<Compile Remove="Listener\ClientListener.cs" />
|
||||
|
@ -42,7 +39,6 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0-preview.6.21352.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Validation" Version="17.0.16-alpha" />
|
||||
<PackageReference Include="Yarp.ReverseProxy" Version="1.0.0-preview.12.21328.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using FastTunnel.Core.Dispatchers;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using FastTunnel.Core.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -15,13 +14,13 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace FastTunnel.Core.Dispatchers
|
||||
{
|
||||
public class ForwardDispatcher : IListenerDispatcher
|
||||
public class ForwardHandler
|
||||
{
|
||||
private FastTunnelServer _server;
|
||||
private WebSocket _client;
|
||||
private ForwardConfig _config;
|
||||
|
||||
public ForwardDispatcher(FastTunnelServer server, WebSocket client, ForwardConfig config)
|
||||
public ForwardHandler(FastTunnelServer server, WebSocket client, ForwardConfig config)
|
||||
{
|
||||
_server = server;
|
||||
_client = client;
|
||||
|
@ -46,10 +45,5 @@ namespace FastTunnel.Core.Dispatchers
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispatch(AsyncUserToken token, string words)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ using System.Net.WebSockets;
|
|||
using FastTunnel.Core.Forwarder;
|
||||
using Microsoft;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using FastTunnel.Core.Server;
|
||||
using System.Data.Common;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Client
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Server
|
||||
{
|
||||
public class HeartMessageHandler : IClientMessageHandler
|
||||
{
|
||||
public bool NeedRecive => true;
|
||||
|
||||
public async Task<bool> HandlerMsg<T>(FastTunnelServer server, WebSocket client, T msg)
|
||||
where T : TunnelMassage
|
||||
{
|
||||
await client.SendCmdAsync(new Message<HeartMassage>() { MessageType = MessageType.Heart, Content = new HeartMassage { } });
|
||||
return NeedRecive;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ using FastTunnel.Core.Dispatchers;
|
|||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Filters;
|
||||
using FastTunnel.Core.Global;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using FastTunnel.Core.Listener;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -94,7 +93,7 @@ namespace FastTunnel.Core.Handlers
|
|||
|
||||
var ls = new PortProxyListener("0.0.0.0", item.RemotePort, _logger);
|
||||
|
||||
ls.Start(new ForwardDispatcher(server, client, item));
|
||||
ls.Start(new ForwardHandler(server, client, item));
|
||||
|
||||
// listen success
|
||||
server.ForwardList.TryAdd(item.RemotePort, new ForwardInfo<ForwardHandlerArg> { Listener = ls, Socket = client, SSHConfig = item });
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
using FastTunnel.Core.Dispatchers;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using FastTunnel.Core.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace FastTunnel.Core.Listener
|
||||
{
|
||||
public class HttpListenerV2
|
||||
{
|
||||
ILogger _logger;
|
||||
|
||||
public string ListenIp { get; protected set; }
|
||||
|
||||
public int ListenPort { get; protected set; }
|
||||
|
||||
IListenerDispatcher _requestDispatcher;
|
||||
public IList<Socket> ConnectedSockets = new List<Socket>();
|
||||
|
||||
Server.Server server;
|
||||
|
||||
public HttpListenerV2(string ip, int port, ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
this.ListenIp = ip;
|
||||
this.ListenPort = port;
|
||||
|
||||
server = new Server.Server(1000, 512, true, _logger);
|
||||
}
|
||||
|
||||
public void Start(IListenerDispatcher requestDispatcher, int backlog = 100)
|
||||
{
|
||||
_requestDispatcher = requestDispatcher;
|
||||
|
||||
IPAddress ipa = IPAddress.Parse(ListenIp);
|
||||
IPEndPoint localEndPoint = new IPEndPoint(ipa, ListenPort);
|
||||
|
||||
server.Init();
|
||||
server.Start(localEndPoint, "\r\n\r\n", handle);
|
||||
_logger.LogInformation($"监听客户端 -> {ListenIp}:{ListenPort}");
|
||||
}
|
||||
|
||||
private bool handle(AsyncUserToken token, string words)
|
||||
{
|
||||
try
|
||||
{
|
||||
_requestDispatcher.Dispatch(token, words);
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCritical(ex, $"【处理HTTP请求异常】{words}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using FastTunnel.Core.Dispatchers;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using FastTunnel.Core.Dispatchers;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -20,7 +19,7 @@ namespace FastTunnel.Core.Listener
|
|||
int m_numConnectedSockets;
|
||||
|
||||
bool shutdown = false;
|
||||
IListenerDispatcher _requestDispatcher;
|
||||
ForwardHandler _requestDispatcher;
|
||||
Socket listenSocket;
|
||||
public IList<Socket> ConnectedSockets = new List<Socket>();
|
||||
|
||||
|
@ -37,7 +36,7 @@ namespace FastTunnel.Core.Listener
|
|||
listenSocket.Bind(localEndPoint);
|
||||
}
|
||||
|
||||
public void Start(IListenerDispatcher requestDispatcher)
|
||||
public void Start(ForwardHandler requestDispatcher)
|
||||
{
|
||||
shutdown = false;
|
||||
_requestDispatcher = requestDispatcher;
|
||||
|
|
|
@ -7,8 +7,8 @@ namespace FastTunnel.Core.Models
|
|||
{
|
||||
public class ForwardHandlerArg
|
||||
{
|
||||
public ForwardConfig SSHConfig { get; internal set; }
|
||||
public ForwardConfig SSHConfig { get; set; }
|
||||
|
||||
public Socket LocalClient { get; internal set; }
|
||||
public Socket LocalClient { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Models
|
||||
{
|
||||
public class HeartMassage : TunnelMassage
|
||||
{
|
||||
public string Time { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Models
|
||||
{
|
||||
public class NewRequest
|
||||
{
|
||||
public Socket CustomerClient { get; set; }
|
||||
public byte[] Buffer { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Handlers;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using FastTunnel.Core.Protocol;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
|
@ -20,8 +19,6 @@ namespace FastTunnel.Core.Models
|
|||
public class TunnelClient
|
||||
{
|
||||
readonly LoginHandler _loginHandler;
|
||||
readonly HeartMessageHandler _heartHandler;
|
||||
//readonly SwapMessageHandler _swapMsgHandler;
|
||||
FastTunnelServer fastTunnelServer;
|
||||
ILogger logger;
|
||||
WebSocket webSocket;
|
||||
|
@ -32,8 +29,6 @@ namespace FastTunnel.Core.Models
|
|||
this.logger = logger;
|
||||
this.fastTunnelServer = fastTunnelServer;
|
||||
this._loginHandler = new LoginHandler(logger, fastTunnelServer.proxyConfig);
|
||||
this._heartHandler = new HeartMessageHandler();
|
||||
// this._swapMsgHandler = new SwapMessageHandler(logger);
|
||||
}
|
||||
|
||||
public async Task ReviceAsync()
|
||||
|
@ -45,6 +40,8 @@ namespace FastTunnel.Core.Models
|
|||
{
|
||||
var res = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
|
||||
var cmds = tunnelProtocol.HandleBuffer(buffer, 0, res.Count);
|
||||
if (cmds == null) continue;
|
||||
|
||||
foreach (var item in cmds)
|
||||
{
|
||||
if (!await HandleCmdAsync(webSocket, item))
|
||||
|
@ -71,9 +68,6 @@ namespace FastTunnel.Core.Models
|
|||
handler = _loginHandler;
|
||||
msg = JsonSerializer.Deserialize<LogInMassage>(cmds[1]);
|
||||
break;
|
||||
case "Heart": // 心跳
|
||||
handler = _heartHandler;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"未知的通讯指令 {lineCmd}");
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Server
|
||||
{
|
||||
public class AsyncUserToken
|
||||
{
|
||||
public Socket Socket { get; set; }
|
||||
|
||||
public string MassgeTemp { get; set; }
|
||||
|
||||
public byte[] Recived { get; set; }
|
||||
|
||||
public string RequestId { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
// This class creates a single large buffer which can be divided up
|
||||
// and assigned to SocketAsyncEventArgs objects for use with each
|
||||
// socket I/O operation.
|
||||
// This enables bufffers to be easily reused and guards against
|
||||
// fragmenting heap memory.
|
||||
//
|
||||
// The operations exposed on the BufferManager class are not thread safe.
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace FastTunnel.Core.Server
|
||||
{
|
||||
class BufferManager
|
||||
{
|
||||
int m_numBytes; // the total number of bytes controlled by the buffer pool
|
||||
byte[] m_buffer; // the underlying byte array maintained by the Buffer Manager
|
||||
Stack<int> m_freeIndexPool; //
|
||||
int m_currentIndex;
|
||||
int m_bufferSize;
|
||||
|
||||
public BufferManager(int totalBytes, int bufferSize)
|
||||
{
|
||||
m_numBytes = totalBytes;
|
||||
m_currentIndex = 0;
|
||||
m_bufferSize = bufferSize;
|
||||
m_freeIndexPool = new Stack<int>();
|
||||
}
|
||||
|
||||
// Allocates buffer space used by the buffer pool
|
||||
public void InitBuffer()
|
||||
{
|
||||
// create one big large buffer and divide that
|
||||
// out to each SocketAsyncEventArg object
|
||||
m_buffer = new byte[m_numBytes];
|
||||
}
|
||||
|
||||
// Assigns a buffer from the buffer pool to the
|
||||
// specified SocketAsyncEventArgs object
|
||||
//
|
||||
// <returns>true if the buffer was successfully set, else false</returns>
|
||||
public bool SetBuffer(SocketAsyncEventArgs args)
|
||||
{
|
||||
if (m_freeIndexPool.Count > 0)
|
||||
{
|
||||
args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_numBytes - m_bufferSize) < m_currentIndex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
|
||||
m_currentIndex += m_bufferSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removes the buffer from a SocketAsyncEventArg object.
|
||||
// This frees the buffer back to the buffer pool
|
||||
public void FreeBuffer(SocketAsyncEventArgs args)
|
||||
{
|
||||
m_freeIndexPool.Push(args.Offset);
|
||||
args.SetBuffer(null, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Pipelines;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Server
|
||||
{
|
||||
public class PipeHepler
|
||||
{
|
||||
Socket m_socket;
|
||||
Func<Socket, byte[], bool> processLine;
|
||||
const int minimumBufferSize = 512;
|
||||
|
||||
public PipeHepler(Socket socket, Func<Socket, byte[], bool> processLine)
|
||||
{
|
||||
this.processLine = processLine;
|
||||
m_socket = socket;
|
||||
}
|
||||
|
||||
public async Task ProcessLinesAsync()
|
||||
{
|
||||
var pipe = new Pipe();
|
||||
Task writing = FillPipeAsync(pipe.Writer);
|
||||
Task reading = ReadPipeAsync(pipe.Reader);
|
||||
await Task.WhenAll(reading, writing);
|
||||
}
|
||||
|
||||
private async Task FillPipeAsync(PipeWriter writer)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Allocate at least 512 bytes from the PipeWriter.
|
||||
Memory<byte> memory = writer.GetMemory(minimumBufferSize);
|
||||
try
|
||||
{
|
||||
int bytesRead = await m_socket.ReceiveAsync(memory, SocketFlags.None);
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Tell the PipeWriter how much was read from the Socket.
|
||||
writer.Advance(bytesRead);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Make the data available to the PipeReader.
|
||||
FlushResult result = await writer.FlushAsync();
|
||||
|
||||
if (result.IsCompleted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// By completing PipeWriter, tell the PipeReader that there's no more data coming.
|
||||
await writer.CompleteAsync();
|
||||
}
|
||||
|
||||
private async Task ReadPipeAsync(PipeReader reader)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ReadResult result = await reader.ReadAsync();
|
||||
ReadOnlySequence<byte> buffer = result.Buffer;
|
||||
|
||||
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
|
||||
{
|
||||
// Process the line.
|
||||
if (!processLine(m_socket, line.ToArray()))
|
||||
{
|
||||
// 停止继续监听
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the PipeReader how much of the buffer has been consumed.
|
||||
reader.AdvanceTo(buffer.Start, buffer.End);
|
||||
|
||||
// Stop reading if there's no more data coming.
|
||||
if (result.IsCompleted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the PipeReader as complete.
|
||||
await reader.CompleteAsync();
|
||||
}
|
||||
|
||||
static bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
|
||||
{
|
||||
// Look for a EOL in the buffer.
|
||||
SequencePosition? position = buffer.PositionOf((byte)'\n');
|
||||
|
||||
if (position == null)
|
||||
{
|
||||
line = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip the line + the \n.
|
||||
line = buffer.Slice(0, position.Value);
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
// Implements the connection logic for the socket server.
|
||||
// After accepting a connection, all data read from the client
|
||||
// is sent back to the client. The read and echo back to the client pattern
|
||||
// is continued until the client disconnects.
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Utility.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace FastTunnel.Core.Server
|
||||
{
|
||||
public class Server
|
||||
{
|
||||
private int m_numConnections; // the maximum number of connections the sample is designed to handle simultaneously
|
||||
private int m_receiveBufferSize;// buffer size to use for each socket I/O operation
|
||||
|
||||
BufferManager m_bufferManager; // represents a large reusable set of buffers for all socket operations
|
||||
const int opsToPreAlloc = 2; // read, write (don't alloc buffer space for accepts)
|
||||
Socket listenSocket; // the socket used to listen for incoming connection requests
|
||||
// pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
|
||||
SocketAsyncEventArgsPool m_readWritePool;
|
||||
//int m_totalBytesRead; // counter of the total # bytes received by the server
|
||||
int m_numConnectedSockets; // the total number of clients connected to the server
|
||||
Semaphore m_maxNumberAcceptedClients;
|
||||
|
||||
Func<AsyncUserToken, string, bool> m_handller;
|
||||
string m_sectionFlag;
|
||||
IPEndPoint _localEndPoint;
|
||||
bool m_isHttpServer;
|
||||
|
||||
ILogger _logger;
|
||||
|
||||
// Create an uninitialized server instance.
|
||||
// To start the server listening for connection requests
|
||||
// call the Init method followed by Start method
|
||||
//
|
||||
// <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
|
||||
// <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
|
||||
public Server(int numConnections, int receiveBufferSize, bool isHttpServer, ILogger logger)
|
||||
{
|
||||
m_isHttpServer = isHttpServer;
|
||||
_logger = logger;
|
||||
//m_totalBytesRead = 0;
|
||||
m_numConnectedSockets = 0;
|
||||
m_numConnections = numConnections;
|
||||
m_receiveBufferSize = receiveBufferSize;
|
||||
// allocate buffers such that the maximum number of sockets can have one outstanding read and
|
||||
// write posted to the socket simultaneously
|
||||
m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
|
||||
receiveBufferSize);
|
||||
|
||||
m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
|
||||
|
||||
m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections);
|
||||
}
|
||||
|
||||
// Initializes the server by preallocating reusable buffers and
|
||||
// context objects. These objects do not need to be preallocated
|
||||
// or reused, but it is done this way to illustrate how the API can
|
||||
// easily be used to create reusable objects to increase server performance.
|
||||
//
|
||||
public void Init()
|
||||
{
|
||||
// Allocates one large byte buffer which all I/O operations use a piece of. This gaurds
|
||||
// against memory fragmentation
|
||||
m_bufferManager.InitBuffer();
|
||||
|
||||
// preallocate pool of SocketAsyncEventArgs objects
|
||||
SocketAsyncEventArgs readWriteEventArg;
|
||||
|
||||
for (int i = 0; i < m_numConnections; i++)
|
||||
{
|
||||
//Pre-allocate a set of reusable SocketAsyncEventArgs
|
||||
readWriteEventArg = new SocketAsyncEventArgs();
|
||||
readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
|
||||
readWriteEventArg.UserToken = new AsyncUserToken();
|
||||
|
||||
// assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
|
||||
m_bufferManager.SetBuffer(readWriteEventArg);
|
||||
|
||||
// add SocketAsyncEventArg to the pool
|
||||
m_readWritePool.Push(readWriteEventArg);
|
||||
}
|
||||
}
|
||||
|
||||
// Starts the server such that it is listening for
|
||||
// incoming connection requests.
|
||||
//
|
||||
// <param name="localEndPoint">The endpoint which the server will listening
|
||||
// for connection requests on</param>
|
||||
public void Start(IPEndPoint localEndPoint, string sectionFlag, Func<AsyncUserToken, string, bool> handller)
|
||||
{
|
||||
m_handller = handller;
|
||||
m_sectionFlag = sectionFlag;
|
||||
_localEndPoint = localEndPoint;
|
||||
|
||||
// create the socket which listens for incoming connections
|
||||
listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
listenSocket.Bind(localEndPoint);
|
||||
// start the server with a listen backlog of 100 connections
|
||||
listenSocket.Listen();
|
||||
|
||||
// post accepts on the listening socket
|
||||
StartAccept(null);
|
||||
}
|
||||
|
||||
// Begins an operation to accept a connection request from the client
|
||||
//
|
||||
// <param name="acceptEventArg">The context object to use when issuing
|
||||
// the accept operation on the server's listening socket</param>
|
||||
public void StartAccept(SocketAsyncEventArgs acceptEventArg)
|
||||
{
|
||||
if (acceptEventArg == null)
|
||||
{
|
||||
acceptEventArg = new SocketAsyncEventArgs();
|
||||
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// socket must be cleared since the context object is being reused
|
||||
acceptEventArg.AcceptSocket = null;
|
||||
}
|
||||
|
||||
m_maxNumberAcceptedClients.WaitOne();
|
||||
|
||||
bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
|
||||
if (!willRaiseEvent)
|
||||
{
|
||||
ProcessAccept(acceptEventArg);
|
||||
}
|
||||
}
|
||||
|
||||
// This method is the callback method associated with Socket.AcceptAsync
|
||||
// operations and is invoked when an accept operation is complete
|
||||
void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
ProcessAccept(e);
|
||||
}
|
||||
|
||||
private void ProcessAccept(SocketAsyncEventArgs e)
|
||||
{
|
||||
Interlocked.Increment(ref m_numConnectedSockets);
|
||||
_logger.LogInformation($"[当前连接数]:{_localEndPoint.Port} | {m_numConnectedSockets}");
|
||||
|
||||
// Get the socket for the accepted client connection and put it into the
|
||||
// ReadEventArg object user token
|
||||
SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
|
||||
var token = readEventArgs.UserToken as AsyncUserToken;
|
||||
token.Socket = e.AcceptSocket;
|
||||
token.MassgeTemp = null;
|
||||
token.Recived = null;
|
||||
|
||||
// 客户端请求不需要分配msgid
|
||||
if (m_isHttpServer)
|
||||
{
|
||||
token.RequestId = $"{DateTime.Now.GetChinaTicks()}_{Guid.NewGuid().ToString().Replace("-", string.Empty)}";
|
||||
_logger.LogDebug($"Accept {token.RequestId}");
|
||||
}
|
||||
|
||||
// As soon as the client is connected, post a receive to the connection
|
||||
bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
|
||||
if (!willRaiseEvent)
|
||||
{
|
||||
ProcessReceive(readEventArgs);
|
||||
}
|
||||
|
||||
// Accept the next connection request
|
||||
StartAccept(e);
|
||||
}
|
||||
|
||||
// This method is called whenever a receive or send operation is completed on a socket
|
||||
//
|
||||
// <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
|
||||
void IO_Completed(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
// determine which type of operation just completed and call the associated handler
|
||||
switch (e.LastOperation)
|
||||
{
|
||||
case SocketAsyncOperation.Receive:
|
||||
ProcessReceive(e);
|
||||
break;
|
||||
case SocketAsyncOperation.Send:
|
||||
ProcessSend(e);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
|
||||
}
|
||||
}
|
||||
|
||||
// This method is invoked when an asynchronous receive operation completes.
|
||||
// If the remote host closed the connection, then the socket is closed.
|
||||
// If data was received then the data is echoed back to the client.
|
||||
//
|
||||
private void ProcessReceive(SocketAsyncEventArgs e)
|
||||
{
|
||||
AsyncUserToken token = (AsyncUserToken)e.UserToken;
|
||||
_logger.LogDebug($"[ProcessReceive]: {_localEndPoint.Port} | {token.RequestId}");
|
||||
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
|
||||
{
|
||||
bool needRecive = false;
|
||||
var words = e.Buffer.GetString(e.Offset, e.BytesTransferred);
|
||||
var sum = token.MassgeTemp + words;
|
||||
|
||||
// 只有http请求需要对已发送字节进行存储
|
||||
if (m_isHttpServer)
|
||||
{
|
||||
if (token.Recived != null)
|
||||
{
|
||||
byte[] resArr = new byte[token.Recived.Length + e.BytesTransferred];
|
||||
token.Recived.CopyTo(resArr, 0);
|
||||
Array.Copy(e.Buffer, e.Offset, resArr, token.Recived.Length, e.BytesTransferred);
|
||||
token.Recived = resArr;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] resArr = new byte[e.BytesTransferred];
|
||||
Array.Copy(e.Buffer, e.Offset, resArr, 0, e.BytesTransferred);
|
||||
token.Recived = resArr;
|
||||
}
|
||||
}
|
||||
|
||||
if (sum.Contains(m_sectionFlag))
|
||||
{
|
||||
var array = (sum).Split(m_sectionFlag);
|
||||
token.MassgeTemp = null;
|
||||
var fullMsg = words.EndsWith(m_sectionFlag);
|
||||
|
||||
if (!fullMsg)
|
||||
{
|
||||
token.MassgeTemp = array[array.Length - 1];
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.Length - 1; i++)
|
||||
{
|
||||
needRecive = m_handller(token, array[i]);
|
||||
if (needRecive)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ÊÍ·Å×ÊÔ´
|
||||
release(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
token.MassgeTemp = sum;
|
||||
}
|
||||
|
||||
bool willRaiseEvent = token.Socket.ReceiveAsync(e);
|
||||
if (!willRaiseEvent)
|
||||
{
|
||||
ProcessReceive(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseClientSocket(e);
|
||||
}
|
||||
}
|
||||
|
||||
// This method is invoked when an asynchronous send operation completes.
|
||||
// The method issues another receive on the socket to read any additional
|
||||
// data sent from the client
|
||||
//
|
||||
// <param name="e"></param>
|
||||
private void ProcessSend(SocketAsyncEventArgs e)
|
||||
{
|
||||
if (e.SocketError == SocketError.Success)
|
||||
{
|
||||
// done echoing data back to the client
|
||||
AsyncUserToken token = (AsyncUserToken)e.UserToken;
|
||||
// read the next block of data send from the client
|
||||
e.SetBuffer(e.Offset, m_receiveBufferSize);
|
||||
bool willRaiseEvent = token.Socket.ReceiveAsync(e);
|
||||
if (!willRaiseEvent)
|
||||
{
|
||||
ProcessReceive(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseClientSocket(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseClientSocket(SocketAsyncEventArgs e)
|
||||
{
|
||||
AsyncUserToken token = e.UserToken as AsyncUserToken;
|
||||
|
||||
// close the socket associated with the client
|
||||
try
|
||||
{
|
||||
token.Socket.Shutdown(SocketShutdown.Send);
|
||||
}
|
||||
// throws if client process has already closed
|
||||
catch (Exception) { }
|
||||
token.Socket.Close();
|
||||
|
||||
release(e);
|
||||
}
|
||||
|
||||
private void release(SocketAsyncEventArgs e)
|
||||
{
|
||||
// decrement the counter keeping track of the total number of clients connected to the server
|
||||
Interlocked.Decrement(ref m_numConnectedSockets);
|
||||
|
||||
_logger.LogInformation($"[SocketCount]:{_localEndPoint.Port} | {m_numConnectedSockets}");
|
||||
// Free the SocketAsyncEventArg so they can be reused by another client
|
||||
m_readWritePool.Push(e);
|
||||
|
||||
m_maxNumberAcceptedClients.Release();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
// Represents a collection of reusable SocketAsyncEventArgs objects.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
|
||||
class SocketAsyncEventArgsPool
|
||||
{
|
||||
Stack<SocketAsyncEventArgs> m_pool;
|
||||
|
||||
// Initializes the object pool to the specified size
|
||||
//
|
||||
// The "capacity" parameter is the maximum number of
|
||||
// SocketAsyncEventArgs objects the pool can hold
|
||||
public SocketAsyncEventArgsPool(int capacity)
|
||||
{
|
||||
m_pool = new Stack<SocketAsyncEventArgs>(capacity);
|
||||
}
|
||||
|
||||
// Add a SocketAsyncEventArg instance to the pool
|
||||
//
|
||||
//The "item" parameter is the SocketAsyncEventArgs instance
|
||||
// to add to the pool
|
||||
public void Push(SocketAsyncEventArgs item)
|
||||
{
|
||||
if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); }
|
||||
lock (m_pool)
|
||||
{
|
||||
m_pool.Push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Removes a SocketAsyncEventArgs instance from the pool
|
||||
// and returns the object removed from the pool
|
||||
public SocketAsyncEventArgs Pop()
|
||||
{
|
||||
lock (m_pool)
|
||||
{
|
||||
return m_pool.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
// The number of SocketAsyncEventArgs instances in the pool
|
||||
public int Count
|
||||
{
|
||||
get { return m_pool.Count; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -26,12 +26,20 @@ namespace FastTunnel.Core.Services
|
|||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_fastTunnelClient.StartAsync(cancellationToken);
|
||||
}, cancellationToken);
|
||||
try
|
||||
{
|
||||
await _fastTunnelClient.StartAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex.Message);
|
||||
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace FastTunnel.Core.Helper
|
||||
{
|
||||
public static class FileHelper
|
||||
{
|
||||
public static byte[] GetBytesFromFile(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FileInfo fi = new FileInfo(fileName);
|
||||
byte[] buff = new byte[fi.Length];
|
||||
|
||||
FileStream fs = fi.OpenRead();
|
||||
fs.Read(buff, 0, Convert.ToInt32(fs.Length));
|
||||
fs.Close();
|
||||
|
||||
return buff;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Helper
|
||||
{
|
||||
public static class ValidateHelper
|
||||
{
|
||||
public static string[] ValidateObject(object instance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FastTunel.Core.WebApi\FastTunel.Core.WebApi.csproj" />
|
||||
<ProjectReference Include="..\FastTunnel.Core\FastTunnel.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastTunnel.Server", "FastTu
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastTunel.Core.WebApi", "FastTunel.Core.WebApi\FastTunel.Core.WebApi.csproj", "{79B1CA3F-D9E9-45F2-8A50-72084B41A0E6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -31,17 +29,12 @@ Global
|
|||
{DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DEF2E322-9075-4C3F-9967-7EAF0EE28CEB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{79B1CA3F-D9E9-45F2-8A50-72084B41A0E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{79B1CA3F-D9E9-45F2-8A50-72084B41A0E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{79B1CA3F-D9E9-45F2-8A50-72084B41A0E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{79B1CA3F-D9E9-45F2-8A50-72084B41A0E6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
|
||||
{79B1CA3F-D9E9-45F2-8A50-72084B41A0E6} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3D9C6B44-6706-4EE8-9043-802BBE474A2E}
|
||||
|
|
Loading…
Reference in New Issue
Block a user