2010-09-01 10 views
14

Estoy usando una cadena de conexión SQL con SqlClient.SqlConnection y especificando Connection Timeout = 5 en la cadena, pero aún espera 30 segundos antes de devolver la falla. ¿Cómo lo hago renunciar y regresar más rápido? Estoy en una red local rápida y no quiero esperar 30 segundos. Los servidores que no están encendidos tardan 30 segundos en fallar. Este es solo un programa de utilidad rápido que siempre se ejecutará solo en esta red local.Cómo hacer que el tiempo de espera de SqlConnection sea más rápido

Editar: Lo siento si no estaba claro. Quiero que el SqlConnection.Open falle más rápido. Espero que eso pueda deducirse del hecho de que los servidores que quiero fallar más rápidamente están apagados.

Editar: Parece que la configuración solo falla a veces. Al igual que sabe la dirección IP del servidor, y está utilizando TCP/IP para hablar con él (no local) pero no puede ponerse en contacto con SQL Server en esa dirección. No estoy seguro de cuál es el patrón, pero no veo el problema cuando se detiene la conexión local con SQL Server, y no lo veo cuando intento conectarme a un servidor que no existe. Lo he visto al intentar contactarme con un servidor donde el firewall de Windows 2008 está bloqueando SQL Server.

Respuesta

10

Parece que todos los casos que estaban causando largas demoras podrían resolverse mucho más rápidamente por intentar establecer una conexión de socket directa como esto:

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); 
    } 
} 

Voy a utilizar este código para comprobar si el servidor responde en el puerto del Servidor SQL, y solo intenta abrir una conexión si lo hace.Pensé (en base a la experiencia de los demás) que habría un retraso de 30 segundos incluso en este nivel, pero recibí un mensaje de que la máquina "rechazó activamente la conexión" en este momento.

Edit: Y si la máquina no existe, me dice eso también de inmediato. No hay demoras de 30 segundos que pueda encontrar.

Edit: Las máquinas que estaban en la red pero no están apagadas todavía tardan 30 segundos en fallar, supongo. Sin embargo, las máquinas cortafuegos fallan más rápido.

Editar: Aquí está el código actualizado. Siento que está más limpia para cerrar una toma de abortar un hilo:

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

Actualización 2 Le sugiero que acumule su propio tiempo de espera. Algo como esto:

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 
     } 
    } 
} 

Actualización 1

acabo de probar esto en mi propio ordenador utilizando este código:

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()); 
     } 
    } 
} 

y obedece el valor Connection Timeout en la cadena de conexión . Esto fue con .NET 4 contra SQL Server 2008 R2. Es cierto que es una conexión localhost que puede dar resultados diferentes pero significa que no puedo replicar el problema.

Solo puedo sugerir intentar una porción similar de código en su entorno de red y ver si continúa viendo tiempos de espera prolongados.

Viejo (incorrecta) respuesta I pensó erróneamente la propiedad ConnectionTimeout era ajustable, pero no lo es.

Pruebe la configuración SqlConnection.ConnectionTimeout en lugar de utilizar la cadena de conexión.

+0

ConnectionTimeout es una propiedad de sólo lectura – BlueMonkMN

+0

estoy golpeando un patrón muy extraño aquí. El tiempo de espera parece funcionar cuando me conecto a mi sistema local con SQL Server detenido. Parece que funciona cuando trato de conectarme a un servidor inexistente. Pero no parece funcionar cuando trato de conectarme a un servidor que existe, pero tiene el firewall bloqueando SQL y/o no tiene instalado SQL Server. – BlueMonkMN

+0

Un hilo interesante sobre este tema aquí: http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.adonet/topic48533.aspx. Sugiero implementar su propio mecanismo de tiempo de espera: escinde un hilo para intentar abrir y matarlo si no ha tenido éxito dentro del período de tiempo de espera deseado. –

0

El tiempo de espera de comando y el tiempo de espera de conexión son dos cosas diferentes.

SqlConnection.ConnectionTimeout es "el tiempo (en segundos) que se debe esperar para que se abra una conexión. El valor predeterminado es 15 segundos." Eso solo se usa cuando llamas a SqlConnection.Open().

El SqlCommand.CommandTimeout hace lo que quiere hacer.

+0

No, no es así. Quiero que el Abierto expire, no un comando. – BlueMonkMN

+0

SqlConnection.ConnectionTimeout es lo que quiere – jrummell

+1

@GBK Puede establecer el tiempo de espera en la cadena de conexión a continuación. Puede usar un [SqlConnectionStringBuilder] (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder.aspx) para analizar y modificar la cadena de conexión antes de pasarla al objeto de conexión. –

Cuestiones relacionadas