public async Task StartHttpService(CancellationTokenSource ctsHttp, int WebManagementPort) { try { HttpListener listener = new HttpListener(); //缓存所有文件 var dir = new DirectoryInfo(BASE_FILE_PATH); var files = dir.GetFiles("*.*"); foreach (var file in files) { using (var fs = file.OpenRead()) { var mms = new MemoryStream(); fs.CopyTo(mms); FilesCache.Add(file.Name, mms); } } Logger.Debug($"{files.Length} files cached."); listener.Prefixes.Add($"http://+:{WebManagementPort}/"); Logger.Debug("Listening HTTP request on port " + WebManagementPort.ToString() + "..."); await AcceptHttpRequest(listener, ctsHttp); } catch (HttpListenerException ex) { Logger.Debug("Please run this program in administrator mode." + ex); Server.Logger.Error(ex.ToString(), ex); } catch (Exception ex) { Logger.Debug(ex); Server.Logger.Error(ex.ToString(), ex); } Logger.Debug("Http服务结束。"); }
/// <summary> /// 重要:连接服务端 /// </summary> /// <returns></returns> public async Task ConnectToProvider() { var appIdIpPortConfig = ClientConfig.Clients; ConnnectionManager = ServerConnnectionManager.Create(); ConnnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected; var clientModel = await ConnnectionManager.InitConfig(); int counter = 0; //appid为0时说明没有分配appid,所以需要分配一个 foreach (var app in appIdIpPortConfig) { if (app.AppId == 0) { app.AppId = clientModel.AppList[counter].AppId; counter++; } } Logger.Debug("****************port list*************"); foreach (var ap in clientModel.AppList) { var cApp = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId); Logger.Debug(ap.AppId.ToString() + ": " + ClientConfig.ProviderAddress + ":" + ap.Port.ToString() + "=>" + cApp.IP + ":" + cApp.TargetServicePort); } Logger.Debug("**************************************"); Task pollingTask = ConnnectionManager.PollingToProvider(); try { await pollingTask; } catch (Exception ex) { Logger.Error("Thread:" + Thread.CurrentThread.ManagedThreadId + " crashed.\n", ex); throw; } await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.Token); }
public async Task StartHttpService(CancellationTokenSource ctsHttp, int WebManagementPort) { try { HttpListener listener = new HttpListener(); listener.Prefixes.Add($"http://+:{WebManagementPort}/"); //TcpListener listenerConfigService = new TcpListener(IPAddress.Any, WebManagementPort); Logger.Debug("Listening HTTP request on port " + WebManagementPort.ToString() + "..."); await AcceptHttpRequest(listener, ctsHttp); } catch (HttpListenerException ex) { Logger.Debug("Please run this program in administrator mode." + ex); Server.Logger.Error(ex.ToString(), ex); } catch (Exception ex) { Logger.Debug(ex); Server.Logger.Error(ex.ToString(), ex); } }
//public static X509Certificate2 TestCert; public async Task Start() { DbOp = new LiteDbOperator(USER_DB_PATH);//加载数据库 //从配置文件加载服务端配置 InitSecureKey(); TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; CancellationTokenSource ctsConfig = new CancellationTokenSource(); CancellationTokenSource ctsHttp = new CancellationTokenSource(); CancellationTokenSource ctsConsumer = new CancellationTokenSource(); //1.反向连接池配置 ConnectionManager = ClientConnectionManager.GetInstance().SetServerContext(ServerContext); //注册客户端发生连接时的事件 ConnectionManager.AppTcpClientMapConfigConnected += ConnectionManager_AppAdded; _ = ConnectionManager.ListenServiceClient(DbOp); Logger.Debug("NSmart server started"); //2.开启http服务 if (ServerContext.ServerConfig.WebAPIPort > 0) { var httpServer = new HttpServer(Logger, DbOp, ServerContext); _ = httpServer.StartHttpService(ctsHttp, ServerContext.ServerConfig.WebAPIPort); } //3.开启心跳检测线程 _ = ProcessHeartbeatsCheck(Global.HeartbeatCheckInterval, ctsConsumer); //3.5 加载SSL证书 Logger.Debug("SSL CA Generating..."); ServerContext.InitCertificates(); Logger.Debug("SSL CA Generated."); //4.开启配置服务(常开) try { await StartConfigService(ctsConfig); } catch (Exception ex) { Logger.Debug(ex.Message); } finally { Logger.Debug("all closed"); ctsConfig.Cancel(); ctsHttp.Cancel(); ctsConsumer.Cancel(); DbOp.Close(); } }
/// <summary> /// 重要:连接服务端,一般做为入口方法 /// 该方法主要操作一些配置和心跳 /// AlwaysReconnect:始终重试,开启此选项,无论何时,一旦程序在连接不上时都会进行重试,否则只在连接成功后的异常中断时才重试。 /// </summary> /// <returns></returns> public async Task Start(bool AlwaysReconnect = false) { if (AlwaysReconnect) { IsStarted = true; } var oneLiveToken = ONE_LIVE_TOKEN_SRC.Token; //登录功能 string arrangedToken = Global.NO_TOKEN_STRING; while (!oneLiveToken.IsCancellationRequested) { CANCEL_TOKEN_SRC = new CancellationTokenSource(); TRANSFERING_TOKEN_SRC = new CancellationTokenSource(); HEARTBEAT_TOKEN_SRC = new CancellationTokenSource(); _waiter = new TaskCompletionSource <object>(); Router.TimeStamp = Guid.NewGuid(); var appIdIpPortConfig = ClientConfig.Clients; int clientId = 0; //0 获取服务器端口配置 try { await InitServerPorts(); } catch (Exception ex)//出错 重连 { if (IsStarted == false) { StatusChanged(ClientStatus.LoginError, null); return; } else { Logger.Error("获取服务器端口失败:" + ex.Message, ex); await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token); continue; } } //0.5 处理登录/重登录/匿名登录逻辑 try { //登录 if (CurrentLoginInfo != null) { var loginResult = await Login(); arrangedToken = loginResult.Item1; clientId = loginResult.Item2; } else if (File.Exists(NspClientCachePath)) { //登录缓存 arrangedToken = File.ReadAllText(NspClientCachePath); //TODO 这个token的合法性无法保证,如果服务端删除了用户,而这里缓存还存在,会导致无法登录 //TODO ***** 这是个trick:防止匿名用户被服务端踢了之后无限申请新账号 //TODO 待解决 版本号无法显示的问题 CurrentLoginInfo = null; } else { //匿名登录,未提供登录信息时,使用空用户名密码自动注册并尝试匿名登录 Router.Logger.Debug("未提供登录信息,尝试匿名登录"); CurrentLoginInfo = new LoginInfo() { UserName = "", UserPwd = "" }; var loginResult = await Login(); arrangedToken = loginResult.Item1; clientId = loginResult.Item2; //保存缓存到磁盘 File.WriteAllText(NspClientCachePath, arrangedToken); } } catch (Exception ex)//出错 重连 { if (IsStarted == false) { StatusChanged(ClientStatus.LoginError, null); return; } else { Logger.Error("启动失败:" + ex.Message, ex); await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token); continue; } } //1.获取配置 ConnectionManager = ServerConnectionManager.Create(clientId); ConnectionManager.CurrentToken = arrangedToken; ConnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected; ConnectionManager.ServerNoResponse = DoServerNoResponse; //下钻事件 ClientModel clientModel = null; // try { //从服务端初始化客户端配置 clientModel = await ConnectionManager.InitConfig(this.ClientConfig).ConfigureAwait(false); } catch (Exception ex) { //TODO 状态码:连接失败 Router.Logger.Error("连接失败:" + ex.Message, ex); //throw; } //HasConnected = true; if (clientModel != null) { int counter = 0; //2.分配配置:appid为0时说明没有分配appid,所以需要分配一个 foreach (var app in appIdIpPortConfig) { if (app.AppId == 0) { app.AppId = clientModel.AppList[counter].AppId; counter++; } } Logger.Debug("****************port list*************"); List <string> tunnelstrs = new List <string>(); foreach (var ap in clientModel.AppList) { var cApp = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId); var tunnelStr = ap.AppId.ToString() + ": " + ClientConfig.ProviderAddress + ":" + ap.Port.ToString() + "=>" + cApp.IP + ":" + cApp.TargetServicePort; Logger.Debug(tunnelStr); tunnelstrs.Add(tunnelStr); } Logger.Debug("**************************************"); _ = ConnectionManager.PollingToProvider(StatusChanged, tunnelstrs); //3.创建心跳连接 _ = ConnectionManager.StartHeartBeats(Global.HeartbeatInterval, HEARTBEAT_TOKEN_SRC.Token, _waiter); IsStarted = true; if (await _waiter.Task.ConfigureAwait(false) is Exception exception) { Router.Logger.Debug($"程序异常终止:{exception.Message}。"); } else { Router.Logger.Debug($"未知异常。"); } } else { Router.Logger.Debug($"程序启动失败。"); //如果程序从未启动过就出错,则终止程序,否则重试。 if (IsStarted == false) { StatusChanged(ClientStatus.Stopped, null); return; } } Router.Logger.Debug($"连接故障,尝试关闭连接并重试"); if (ConnectionManager != null) { ConnectionManager.CloseAllConnections();//关闭所有连接 } //出错重试 await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token); //TODO 返回错误码 //await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.CurrentToken).ConfigureAwait(false); Router.Logger.Debug($"连接关闭,开启重试"); } //正常终止 Router.Logger.Debug($"停止重试,循环终止。"); }
/// <summary> /// 重要:连接服务端,一般做为入口方法 /// 该方法主要操作一些配置和心跳 /// </summary> /// <returns></returns> public async Task Start() { var oneLiveToken = ONE_LIVE_TOKEN_SRC.Token; while (!oneLiveToken.IsCancellationRequested) { CANCEL_TOKEN_SRC = new CancellationTokenSource(); TRANSFERING_TOKEN_SRC = new CancellationTokenSource(); HEARTBEAT_TOKEN_SRC = new CancellationTokenSource(); _waiter = new TaskCompletionSource <object>(); var appIdIpPortConfig = ClientConfig.Clients; int clientId = 0; //0.5 如果有文件,取出缓存中的clientid try { if (File.Exists(NSMART_CLIENT_CACHE_PATH)) { using (var stream = File.OpenRead(NSMART_CLIENT_CACHE_PATH)) { byte[] bytes = new byte[2]; stream.Read(bytes, 0, bytes.Length); clientId = StringUtil.DoubleBytesToInt(bytes); } } } catch (Exception ex) { Logger.Error(ex.Message, ex); } //1.获取配置 ConnectionManager = ServerConnnectionManager.Create(clientId); ConnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected; ConnectionManager.ServerNoResponse = DoServerNoResponse; //下钻事件 ClientModel clientModel = null; // try { //非第一次则算作重连,发送clientid过去 clientModel = await ConnectionManager.InitConfig(this.ClientConfig).ConfigureAwait(false); } catch (Exception ex) { //TODO 状态码:连接失败 Router.Logger.Error("连接失败:" + ex.Message, ex); //throw; } //HasConnected = true; if (clientModel != null) { int counter = 0; //1.5 写入缓存 File.WriteAllBytes(NSMART_CLIENT_CACHE_PATH, StringUtil.IntTo2Bytes(clientModel.ClientId)); //2.分配配置:appid为0时说明没有分配appid,所以需要分配一个 foreach (var app in appIdIpPortConfig) { if (app.AppId == 0) { app.AppId = clientModel.AppList[counter].AppId; counter++; } } Logger.Debug("****************port list*************"); List <string> tunnelstrs = new List <string>(); foreach (var ap in clientModel.AppList) { var cApp = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId); var tunnelStr = ap.AppId.ToString() + ": " + ClientConfig.ProviderAddress + ":" + ap.Port.ToString() + "=>" + cApp.IP + ":" + cApp.TargetServicePort; Logger.Debug(tunnelStr); tunnelstrs.Add(tunnelStr); } Logger.Debug("**************************************"); ConnectionManager.PollingToProvider(StatusChanged, tunnelstrs); //3.创建心跳连接 ConnectionManager.StartHeartBeats(Global.HeartbeatInterval, HEARTBEAT_TOKEN_SRC.Token); //try //{ // await pollingTask.ConfigureAwait(false); //} //catch (Exception ex) //{ // Logger.Error("Thread:" + Thread.CurrentThread.ManagedThreadId + " crashed.\n", ex); // throw; //} IsStarted = true; Exception exception = await _waiter.Task.ConfigureAwait(false) as Exception; Router.Logger.Debug($"程序异常终止:{exception.Message}。"); } else { Router.Logger.Debug($"程序启动失败。"); //如果程序从未启动过就出错,则终止程序,否则重试。 if (IsStarted == false) { StatusChanged(ClientStatus.Stopped, null); return; } } //出错重试 await Task.Delay(3000, ONE_LIVE_TOKEN_SRC.Token); //TODO 返回错误码 //await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.Token).ConfigureAwait(false); } //正常终止 }
/// <summary> /// 重要:连接服务端,一般做为入口方法 /// 该方法主要操作一些配置和心跳 /// AlwaysReconnect:始终重试,开启此选项,无论何时,一旦程序在连接不上时都会进行重试,否则只在连接成功后的断线时才重试。 /// </summary> /// <returns></returns> public async Task Start(bool AlwaysReconnect = false) { if (AlwaysReconnect) { IsStarted = true; } var oneLiveToken = ONE_LIVE_TOKEN_SRC.Token; //登陆功能 string arrangedToken = Global.NO_TOKEN_STRING; while (!oneLiveToken.IsCancellationRequested) { CANCEL_TOKEN_SRC = new CancellationTokenSource(); TRANSFERING_TOKEN_SRC = new CancellationTokenSource(); HEARTBEAT_TOKEN_SRC = new CancellationTokenSource(); _waiter = new TaskCompletionSource <object>(); var appIdIpPortConfig = ClientConfig.Clients; int clientId = 0; //0.5 如果有文件,取出缓存中的clientid try { //登陆缓存 if (File.Exists(NSMART_CLIENT_CACHE_PATH)) { using (var stream = File.OpenRead(NSMART_CLIENT_CACHE_PATH)) { byte[] bytes = new byte[2]; stream.Read(bytes, 0, bytes.Length); clientId = StringUtil.DoubleBytesToInt(bytes); } } //登陆 if (CurrentLoginInfo != null) { NSPDispatcher disp = new NSPDispatcher(); var result = await disp.LoginFromClient(CurrentLoginInfo.UserName, CurrentLoginInfo.UserPwd); if (result.State == 1) { Router.Logger.Debug("登陆成功"); var data = result.Data; arrangedToken = data.Token; Router.Logger.Debug($"服务端版本号:{data.Version},当前适配版本号{Global.NSmartProxyServerName}"); clientId = int.Parse(data.Userid); } else { throw new Exception("登陆失败,服务端返回错误如下:" + result.Msg); } } else { Router.Logger.Debug("为提供登陆信息,尝试匿名登陆"); } } catch (Exception ex) { Logger.Error(ex.Message, ex); } //1.获取配置 ConnectionManager = ServerConnectionManager.Create(clientId); ConnectionManager.CurrentToken = arrangedToken; ConnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected; ConnectionManager.ServerNoResponse = DoServerNoResponse; //下钻事件 ClientModel clientModel = null; // try { //非第一次则算作重连,发送clientid过去 clientModel = await ConnectionManager.InitConfig(this.ClientConfig).ConfigureAwait(false); } catch (Exception ex) { //TODO 状态码:连接失败 Router.Logger.Error("连接失败:" + ex.Message, ex); //throw; } //HasConnected = true; if (clientModel != null) { int counter = 0; //1.5 写入缓存 File.WriteAllBytes(NSMART_CLIENT_CACHE_PATH, StringUtil.IntTo2Bytes(clientModel.ClientId)); //2.分配配置:appid为0时说明没有分配appid,所以需要分配一个 foreach (var app in appIdIpPortConfig) { if (app.AppId == 0) { app.AppId = clientModel.AppList[counter].AppId; counter++; } } Logger.Debug("****************port list*************"); List <string> tunnelstrs = new List <string>(); foreach (var ap in clientModel.AppList) { var cApp = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId); var tunnelStr = ap.AppId.ToString() + ": " + ClientConfig.ProviderAddress + ":" + ap.Port.ToString() + "=>" + cApp.IP + ":" + cApp.TargetServicePort; Logger.Debug(tunnelStr); tunnelstrs.Add(tunnelStr); } Logger.Debug("**************************************"); ConnectionManager.PollingToProvider(StatusChanged, tunnelstrs); //3.创建心跳连接 ConnectionManager.StartHeartBeats(Global.HeartbeatInterval, HEARTBEAT_TOKEN_SRC.Token); IsStarted = true; Exception exception = await _waiter.Task.ConfigureAwait(false) as Exception; if (exception != null) { Router.Logger.Debug($"程序异常终止:{exception.Message}。"); } else { Router.Logger.Debug($"未知异常。"); } } else { Router.Logger.Debug($"程序启动失败。"); //如果程序从未启动过就出错,则终止程序,否则重试。 if (IsStarted == false) { StatusChanged(ClientStatus.Stopped, null); return; } } Router.Logger.Debug($"连接故障,尝试关闭连接并重试"); if (ConnectionManager != null) { ConnectionManager.CloseAllConnections();//关闭所有连接 } //出错重试 await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token); //TODO 返回错误码 //await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.CurrentToken).ConfigureAwait(false); Router.Logger.Debug($"连接关闭,开启重试"); } //正常终止 Router.Logger.Debug($"停止重试,循环终止。"); }
public async Task Start() { TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; CancellationTokenSource ctsConfig = new CancellationTokenSource(); CancellationTokenSource ctsHttp = new CancellationTokenSource(); CancellationTokenSource ctsConsumer = new CancellationTokenSource(); //1.反向连接池配置 ConnectionManager = ClientConnectionManager.GetInstance(); //注册客户端发生连接时的事件 ConnectionManager.AppTcpClientMapConfigConnected += ConnectionManager_AppAdded; Logger.Debug("NSmart server started"); //2.开启http服务 if (WebManagementPort > 0) { var httpServer = new HttpServer(Logger); httpServer.StartHttpService(ctsHttp, WebManagementPort); } //3.开启心跳检测线程 ProcessHeartbeatsCheck(Global.HeartbeatCheckInterval, ctsConsumer); //4.开启配置服务(常开) try { await StartConfigService(ctsConfig); } catch (Exception ex) { Logger.Debug(ex.Message); } finally { Logger.Debug("all closed"); ctsConfig.Cancel(); ctsHttp.Cancel(); ctsConsumer.Cancel(); } }
public async Task Start() { TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; CancellationTokenSource ctsConfig = new CancellationTokenSource(); CancellationTokenSource ctsHttp = new CancellationTokenSource(); CancellationTokenSource ctsConsumer = new CancellationTokenSource(); //1.反向连接池配置 ConnectionManager = ClientConnectionManager.GetInstance(); //注册客户端发生连接时的事件 ConnectionManager.AppTcpClientMapConfigConnected += ConnectionManager_AppAdded; Logger.Debug("NSmart server started"); //2.开启http服务 if (WebManagementPort > 0) { StartHttpService(ctsHttp); } //3.开启配置服务 try { await StartConfigService(ctsConfig); } catch (Exception ex) { Logger.Debug(ex.Message); } finally { Logger.Debug("all closed"); ctsConfig.Cancel(); //listenerConsumer.Stop(); } ////4.通过已配置的端口集合开启侦听 //foreach (var kv in ConnectionManager.PortAppMap) //{ // ListenConsumeAsync(kv.Key, ctsConsumer.Token); //} }