예제 #1
0
        /// <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($"停止重试,循环终止。");
        }
예제 #2
0
        /// <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($"停止重试,循环终止。");
        }