为什么在这种情况下会忽略ConnectTimeout?

时间:2011-11-17 15:48:54

标签: sql-server ado.net

运行此代码时:

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";

1 个答案:

答案 0 :(得分:7)

编辑:这看起来很奇怪,我在反编译代码中加入了一个断点,并使用 - > VALID &lt将设置为超时; - 服务器名称,我让我的断点坐在那里然后继续,它给出超时过期异常按预期所以似乎ConnectTimeout仅在它能够解析服务器并等待时才适用用于连接。 不会影响解析服务器以连接到。我认为正在经历的时间是服务器解析而不是实际的“连接”行为。至少这是我目前的假设。

我用反射器看看封面下发生了什么。也许来自 Microsoft 的人可以帮助我们,因为我还发现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, DbConnectionPool pool, 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, "", 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, poolGroupProviderInfo, "", (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, connectionOptions, 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, string newPassword, bool redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, 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, newPassword, true, timeout, 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, newPassword, redirectedUserInstance, owningObject, connectionOptions, timeout);
          return;
        }
        if (Bid.AdvancedOn)
        {
          Bid.Trace("<sc.SqlInternalConnectionTds.LoginNoFailover|ADV> %d#, sleeping %d{milisec}\n", base.ObjectID, num);
        }
        Thread.Sleep(num);
        num = (num < 500) ? (num * 2) : 0x3e8;
      }
      if (this.PoolGroupProviderInfo != null)
      {
        this.PoolGroupProviderInfo.FailoverCheck(this, false, connectionOptions, 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, false, 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, ignoreSniOpenTimeout, timerExpire, out instanceName, integratedSecurity, this._sniServerUserName, false, 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, ignoreSniOpenTimeout, timerExpire, out instanceName, integratedSecurity, this._sniServerUserName, true, 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, trustServerCert, 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似乎是真的。

不确定这是否有帮助,但我认为值得深入研究

enter image description here

enter image description here