2010-09-01 16 views
14

Utilizzo una stringa di connessione SQL con SqlClient.SqlConnection e specifica Timeout di connessione = 5 nella stringa, ma attende ancora 30 secondi prima di restituire un errore. Come faccio a rinunciare e tornare più veloce? Sono su una rete locale veloce e non voglio aspettare 30 secondi. I server che non sono attivi impiegano 30 secondi per fallire. Questo è solo un programma di utilità rapido che verrà sempre eseguito solo su questa rete locale.Come rendere più veloce il timeout di SqlConnection

Modifica: Scusa se non sono stato chiaro. Voglio che SqlConnection.Open fallisca più velocemente. Si spera che ciò possa essere dedotto dal fatto che i server che voglio fallire più velocemente sono disattivati.

Modifica: A volte l'impostazione non riesce. Come se fosse a conoscenza dell'indirizzo IP del server e utilizza TCP/IP per comunicare con esso (non locale) ma non può contattare SQL Server a tale indirizzo? Non sono sicuro di quale sia lo schema, ma non vedo il problema quando si connette localmente con SQL Server interrotto e non lo vedo quando si tenta di connettersi a un server inesistente. L'ho visto quando tento di contattare un server in cui il firewall di Windows 2008 sta bloccando SQL Server, però.

risposta

10

Sembra che tutti i casi che stavano causando lunghi ritardi potrebbero essere risolti molto più rapidamente tentando una connessione socket diretta in questo modo:

foreach (string svrName in args) 
{ 
    try 
    { 
     System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient(svrName, 1433); 
     if (tcp.Connected) 
     Console.WriteLine("Opened connection to {0}", svrName); 
     else 
     Console.WriteLine("{0} not connected", svrName); 
     tcp.Close(); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Error connecting to {0}: {1}", svrName, ex.Message); 
    } 
} 

ho intenzione di utilizzare questo codice per verificare se il server risponde sulla porta di SQL Server e tenta solo di aprire una connessione se lo fa.Ho pensato (in base all'esperienza altrui) che ci sarebbe stato un ritardo di 30 secondi anche a questo livello, ma ho ricevuto un messaggio che la macchina "ha rifiutato attivamente la connessione" su questi subito.

Modifica: E se la macchina non esiste, mi dice subito anche questo. Nessun ritardo di 30 secondi che riesco a trovare.

Modifica: Le macchine che erano sulla rete ma non sono disattivate richiedono ancora 30 secondi per fallire, suppongo. Le macchine con firewall falliscono più velocemente, però.

Modifica: Ecco il codice aggiornato. Mi sento come se fosse più pulito per chiudere un socket di abortire un filo:

static void TestConn(string server) 
{ 
    try 
    { 
     using (System.Net.Sockets.TcpClient tcpSocket = new System.Net.Sockets.TcpClient()) 
     { 
     IAsyncResult async = tcpSocket.BeginConnect(server, 1433, ConnectCallback, null); 
     DateTime startTime = DateTime.Now; 
     do 
     { 
      System.Threading.Thread.Sleep(500); 
      if (async.IsCompleted) break; 
     } while (DateTime.Now.Subtract(startTime).TotalSeconds < 5); 
     if (async.IsCompleted) 
     { 
      tcpSocket.EndConnect(async); 
      Console.WriteLine("Connection succeeded"); 
     } 
     tcpSocket.Close(); 
     if (!async.IsCompleted) 
     { 
      Console.WriteLine("Server did not respond"); 
      return; 
     } 
     } 
    } 
    catch(System.Net.Sockets.SocketException ex) 
    { 
     Console.WriteLine(ex.Message); 
    } 
} 
3

Aggiornamento 2 Suggerisco di eseguire il proprio timeout. Qualcosa di simile a questo:

internal static class Program 
{ 
    private static void Main(string[] args) 
    { 
     Console.WriteLine(SqlServerIsRunning("Server=foobar; Database=tempdb; Integrated Security=true", 5)); 
     Console.WriteLine(SqlServerIsRunning("Server=localhost; Database=tempdb; Integrated Security=true", 5)); 
    } 

    private static bool SqlServerIsRunning(string baseConnectionString, int timeoutInSeconds) 
    { 
     bool result; 

     using (SqlConnection sqlConnection = new SqlConnection(baseConnectionString + ";Connection Timeout=" + timeoutInSeconds)) 
     { 
      Thread thread = new Thread(TryOpen); 
      ManualResetEvent manualResetEvent = new ManualResetEvent(false); 
      thread.Start(new Tuple<SqlConnection, ManualResetEvent>(sqlConnection, manualResetEvent)); 
      result = manualResetEvent.WaitOne(timeoutInSeconds*1000); 

      if (!result) 
      { 
       thread.Abort(); 
      } 

      sqlConnection.Close(); 
     } 

     return result; 
    } 

    private static void TryOpen(object input) 
    { 
     Tuple<SqlConnection, ManualResetEvent> parameters = (Tuple<SqlConnection, ManualResetEvent>)input; 

     try 
     { 
      parameters.Item1.Open(); 
      parameters.Item1.Close(); 
      parameters.Item2.Set(); 
     } 
     catch 
     { 
      // Eat any exception, we're not interested in it 
     } 
    } 
} 

Update 1

Ho appena testato questo sul mio computer utilizzando questo codice:

internal static class Program 
{ 
    private static void Main(string[] args) 
    { 
     SqlConnection con = new SqlConnection("Server=localhost; Database=tempdb; Integrated Security=true;Connection Timeout=5"); 
     Console.WriteLine("Attempting to open connection with {0} second timeout, starting at {1}.", con.ConnectionTimeout, DateTime.Now.ToLongTimeString()); 

     try 
     { 
      con.Open(); 
      Console.WriteLine("Successfully opened connection at {0}.", DateTime.Now.ToLongTimeString()); 
     } 
     catch (SqlException) 
     { 
      Console.WriteLine("SqlException raised at {0}.", DateTime.Now.ToLongTimeString()); 
     } 
    } 
} 

e obbedisce il valore Connection Timeout nella stringa di connessione . Questo era con .NET 4 contro SQL Server 2008 R2. Certo, è una connessione localhost che può dare risultati diversi ma significa che non posso replicare il problema.

Posso solo suggerire di provare un pezzo simile di codice nell'ambiente di rete e vedere se continui a vedere lunghi timeout.

Vecchio (errato) risposta ho erroneamente pensato che la proprietà era ConnectionTimeout impostabile, ma non lo è.

Provare a impostare SqlConnection.ConnectionTimeout anziché utilizzare la stringa di connessione.

+0

ConnectionTimeout è una proprietà di sola lettura – BlueMonkMN

+0

sto colpendo un modello molto strano qui. Il timeout sembra funzionare quando mi collego al mio sistema locale con SQL Server interrotto. Sembra funzionare quando provo a connettermi a un server inesistente. Ma non sembra funzionare quando provo a collegarmi a un server esistente, ma ha il firewall che blocca SQL e/o non ha installato SQL Server. – BlueMonkMN

+0

Un thread interessante su questo problema qui: http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.adonet/topic48533.aspx. Suggerisco di implementare il proprio meccanismo di timeout: spegni un thread per provare a fare l'open e ucciderlo se non ha avuto successo entro il periodo di timeout desiderato. –

0

Il Timeout del comando e il Timeout della connessione sono due cose diverse.

SqlConnection.ConnectionTimeout è "il tempo (in secondi) di attesa per l'apertura di una connessione. Il valore predefinito è 15 secondi." Questo è usato solo quando si chiama SqlConnection.Open().

SqlCommand.CommandTimeout esegue ciò che si desidera.

+0

No, non lo è. Voglio che l'Open torni in timeout, non un comando. – BlueMonkMN

+0

SqlConnection.ConnectionTimeout è ciò che si desidera – jrummell

+1

@ GBK Quindi è possibile impostare il timeout sulla stringa di connessione. È possibile utilizzare [SqlConnectionStringBuilder] (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder.aspx) per analizzare e modificare la stringa di connessione prima di passarla all'oggetto di connessione. –

Problemi correlati