运行此代码时:
static void Main(string[] args) { sqlConnectionStringBuilder csb = new sqlConnectionStringBuilder(); csb.DataSource = @"8.8.8.8"; // some inaccessible ip address csb.InitialCatalog = "Tempdb"; csb.IntegratedSecurity = true; csb.ConnectTimeout = 1; DateTime start = DateTime.Now; try { new sqlConnection(csb.ToString()).Open(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { Console.Write(string.Format("{0} seconds",DateTime.Now.Subtract(start).TotalSeconds)); } }
我得到这个结果:
A network-related or instance-specific error occurred while establishing a connection to sql Server. The server was not found or was not accessible. Verify that the instance name is correct and that sql Server is configured to allow remote connections. (provider: Named Pipes Provider,error: 40 - Could not open a connection to sql Server) 47.6097605 seconds
我希望ConnectTimeout属性有效.那么为什么在这种情况下会忽略ConnectTimeout属性? (我也很好奇其他人看到的时间).
更新:我注意到以下额外的行将时间跨度缩短到26秒???
csb.FailoverPartner=@"9.9.9.9";
解决方法
编辑:虽然看起来很奇怪,但我在反编译代码中加入了一个断点并使用 – > VALID< - 服务器名称将超时设置为1,我让断点坐在那里然后继续,然后它按预期给出超时过期异常所以看起来ConnectTimeout仅在能够解析服务器并等待连接时才适用.它不会影响解析要连接的服务器.我认为现在经历的是服务器解析而不是实际的“连接”行为.至少这是我目前的假设. 我用反射器看看封面下发生了什么.也许微软的某些人可以帮助我们,因为我还发现ConnectTimeout似乎对初始连接没有影响. 无论如何在内部建立连接,调用以下方法,按此顺序我想:
internal DbConnectionInternal CreatePooledConnection(DbConnection owningConnection,DbConnectionPool pool,DbConnectionOptions options) { DbConnectionPoolGroupProviderInfo providerInfo = pool.PoolGroup.ProviderInfo; DbConnectionInternal internal2 = this.CreateConnection(options,providerInfo,pool,owningConnection); if (internal2 != null) { this.PerformanceCounters.HardConnectsPerSecond.Increment(); internal2.MakePooledConnection(pool); } Bid.Trace("<prov.DbConnectionFactory.CreatePooledConnection|RES|CPOOL> %d#,Pooled database connection created.\n",this.ObjectID); return internal2; }
然后:
protected override DbConnectionInternal CreateConnection(DbConnectionOptions options,object poolGroupProviderInfo,DbConnection owningConnection) { string instanceName; sqlConnectionString str = (sqlConnectionString) options; if (str.ContextConnection) { return this.GetContextConnection(str,poolGroupProviderInfo,owningConnection); } bool redirectedUserInstance = false; DbConnectionPoolIdentity current = null; if (str.IntegratedSecurity) { if (pool != null) { current = pool.Identity; } else { current = DbConnectionPoolIdentity.GetCurrent(); } } if (!str.UserInstance) { goto Label_00F1; } redirectedUserInstance = true; if ((pool == null) || ((pool != null) && (pool.Count <= 0))) { using (sqlInternalConnectionTds tds = null) { sqlConnectionString connectionOptions = new sqlConnectionString(str,str.DataSource,true,false); tds = new sqlInternalConnectionTds(current,connectionOptions,null,"",false); instanceName = tds.InstanceName; if (!instanceName.StartsWith(@"\\.\",StringComparison.Ordinal)) { throw sql.NonLocalSSEInstance(); } if (pool != null) { sqlConnectionPoolProviderInfo info2 = (sqlConnectionPoolProviderInfo) pool.ProviderInfo; info2.InstanceName = instanceName; } goto Label_00DB; } } sqlConnectionPoolProviderInfo providerInfo = (sqlConnectionPoolProviderInfo) pool.ProviderInfo; instanceName = providerInfo.InstanceName; Label_00DB: str = new sqlConnectionString(str,instanceName,false,null); poolGroupProviderInfo = null; Label_00F1: return new sqlInternalConnectionTds(current,str,(sqlConnection) owningConnection,redirectedUserInstance); }
然后:
internal sqlInternalConnectionTds(DbConnectionPoolIdentity identity,sqlConnectionString connectionOptions,object providerInfo,string newPassword,sqlConnection owningObject,bool redirectedUserInstance) : base(connectionOptions) { this._instanceName = string.Empty; if (connectionOptions.UserInstance && InOutOfProcHelper.InProc) { throw sql.UserInstanceNotAvailableInProc(); } this._identity = identity; this._poolGroupProviderInfo = (sqlConnectionPoolGroupProviderInfo) providerInfo; this._fResetConnection = connectionOptions.ConnectionReset; if (this._fResetConnection) { this._originalDatabase = connectionOptions.InitialCatalog; this._originalLanguage = connectionOptions.CurrentLanguage; } RuntimeHelpers.PrepareConstrainedRegions(); try { TimeoutTimer timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); this.OpenLoginEnlist(owningObject,timeout,newPassword,redirectedUserInstance); } catch (OutOfMemoryException) { base.DoomThisConnection(); throw; } catch (StackOverflowException) { base.DoomThisConnection(); throw; } catch (ThreadAbortException) { base.DoomThisConnection(); throw; } if (Bid.AdvancedOn) { Bid.Trace("<sc.sqlInternalConnectionTds.ctor|ADV> %d#,constructed new TDS internal connection\n",base.ObjectID); } }
然后,默认情况下(没有故障转移伙伴):
private void LoginNoFailover(ServerInfo serverInfo,bool redirectedUserInstance,TimeoutTimer timeout) { if (Bid.AdvancedOn) { Bid.Trace("<sc.sqlInternalConnectionTds.LoginNoFailover|ADV> %d#,host=%ls\n",base.ObjectID,serverInfo.UserServerName); } int num = 100; this.ResolveExtendedServerName(serverInfo,!redirectedUserInstance,owningObject); while (true) { if (this._parser != null) { this._parser.Disconnect(); } this._parser = new TdsParser(base.ConnectionOptions.MARS,base.ConnectionOptions.Asynchronous); try { this.AttemptOneLogin(serverInfo,owningObject); break; } catch (sqlException exception) { if (((this._parser == null) || (this._parser.State != TdsParserState.Closed)) || (this.IsDoNotRetryConnectError(exception.Number) || timeout.IsExpired)) { throw; } if (timeout.MillisecondsRemaining <= num) { throw; } } if (this.ServerProvidedFailOverPartner != null) { this.LoginWithFailover(true,serverInfo,this.ServerProvidedFailOverPartner,redirectedUserInstance,owningObject,timeout); return; } if (Bid.AdvancedOn) { Bid.Trace("<sc.sqlInternalConnectionTds.LoginNoFailover|ADV> %d#,sleeping %d{milisec}\n",num); } Thread.Sleep(num); num = (num < 500) ? (num * 2) : 0x3e8; } if (this.PoolGroupProviderInfo != null) { this.PoolGroupProviderInfo.FailoverCheck(this,this.ServerProvidedFailOverPartner); } base.CurrentDataSource = serverInfo.UserServerName; }
然后:
internal void Connect(ServerInfo serverInfo,sqlInternalConnectionTds connHandler,bool ignoreSniOpenTimeout,long timerExpire,bool encrypt,bool trustServerCert,bool integratedSecurity) { if (this._state == TdsParserState.Closed) { this._connHandler = connHandler; if (SNILoadHandle.SingletonInstance.SNIStatus != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); this._physicalStateObj.Dispose(); this.ThrowExceptionAndWarning(); } if (integratedSecurity) { this.LoadSSPILibrary(); this._sniServerUserName = new byte[s_maxSSPILength]; Bid.Trace("<sc.TdsParser.Connect|SEC> SSPI authentication\n"); } else { Bid.Trace("<sc.TdsParser.Connect|SEC> sql authentication\n"); } byte[] instanceName = null; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName,ignoreSniOpenTimeout,timerExpire,out instanceName,integratedSecurity,this._sniServerUserName,this._fAsync); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); this._physicalStateObj.Dispose(); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } this._server = serverInfo.ResolvedServerName; if (connHandler.PoolGroupProviderInfo != null) { connHandler.PoolGroupProviderInfo.AliasCheck(serverInfo.ResolvedServerName); } this._state = TdsParserState.OpenNotLoggedIn; this._physicalStateObj.SniContext = SniContext.Snix_PreLoginBeforeSuccessfullWrite; this._physicalStateObj.TimeoutTime = timerExpire; bool marsCapable = false; this.SendPreLoginHandshake(instanceName,encrypt); this._physicalStateObj.SniContext = SniContext.Snix_PreLogin; switch (this.ConsumePreLoginHandshake(encrypt,trustServerCert,out marsCapable)) { case PreLoginHandshakeStatus.SphinxFailure: this._fMARS = false; this._physicalStateObj._sniPacket = null; this._physicalStateObj.SniContext = SniContext.Snix_Connect; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName,this._fAsync); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } break; case PreLoginHandshakeStatus.InstanceFailure: this._physicalStateObj.Dispose(); this._physicalStateObj.SniContext = SniContext.Snix_Connect; this._physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName,this._fAsync); if (this._physicalStateObj.Status != 0) { this.Errors.Add(this.ProcessSNIError(this._physicalStateObj)); Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); this.ThrowExceptionAndWarning(); } this.SendPreLoginHandshake(instanceName,encrypt); if (this.ConsumePreLoginHandshake(encrypt,out marsCapable) == PreLoginHandshakeStatus.InstanceFailure) { Bid.Trace("<sc.TdsParser.Connect|ERR|SEC> Login failure\n"); throw sql.InstanceFailure(); } break; } if (this._fMARS && marsCapable) { this._sessionPool = new TdsParserSessionPool(this); } else { this._fMARS = false; } } }
我不确定这一切是如何组合在一起的,但是infiniteTimeout似乎是真的.
不确定这是否有帮助,但我认为值得挖掘