Подтвердить что ты не робот

Как сделать тайм-аут SqlConnection более быстрым

Я использую строку соединения SQL с SqlClient.SqlConnection и указывая время ожидания соединения = 5 в строке, но она все еще ждет 30 секунд перед возвратом отказа. Как мне заставить его сдаться и вернуться быстрее? Я нахожусь в быстрой локальной сети и не хочу ждать 30 секунд. Серверы, которые не включены, задерживают 30 секунд. Это просто программа для быстрой утилиты, которая всегда будет работать только в этой локальной сети.

Изменить: Извините, если я не понял. Я хочу, чтобы SqlConnection.Open терпел неудачу быстрее. Надеюсь, это можно было бы вывести из того факта, что серверы, которые я хочу сбой быстрее, отключены.

Изменить. Кажется, что настройка иногда не срабатывает. Как он знает IP-адрес сервера и использует TCP/IP для разговора (не локальный), но не может связаться с SQL Server по этому адресу? Я не уверен, что такое шаблон, но я не вижу проблемы при локальном подключении с SQL Server, и я не вижу его при попытке подключиться к несуществующему серверу. Я видел это при попытке связаться с сервером, где брандмауэр Windows 2008 блокирует SQL Server.

4b9b3361

Ответ 1

Похоже, что все случаи, которые вызывают длительные задержки, могут быть разрешены гораздо быстрее, пытаясь установить прямое соединение со следующим:

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

Я собираюсь использовать этот код, чтобы проверить, отвечает ли сервер на порт SQL Server, и только пытайтесь открыть соединение, если это произойдет. Я подумал (по опыту других), что на этом уровне будет 30-секундная задержка, но я получаю сообщение о том, что машина "активно отказалась от соединения" сразу после этого.

Изменить: И если машина не существует, она сразу же сообщает мне об этом. Нет 30-секундных задержек, которые я могу найти.

Изменить: Машины, которые были в сети, но не отключены, до сих пор занимают 30 секунд. Однако брандмауэр-машины работают быстрее.

Изменить: Здесь обновленный код. Я чувствую, что это чище, чтобы закрыть сокет, чем прервать поток:

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

Ответ 2

Обновление 2 Я предлагаю перевести свой тайм-аут. Что-то вроде этого:

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

Обновление 1

Я только что протестировал это на своем собственном компьютере, используя этот код:

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

и он соответствует значению Connection Timeout в строке подключения. Это было с .NET 4 против SQL Server 2008 R2. По общему признанию, это соединение с localhost, которое может давать разные результаты, но это означает, что я не могу реплицировать проблему.

Я могу только предположить, пытаясь аналогичный фрагмент кода в сетевой среде и, видя, если вы будете продолжать видеть длинные перерывы.

Старый (неверный) ответ Я неправильно думал, что свойство ConnectionTimeout можно установить, но это не так.

Попробуйте установить SqlConnection.ConnectionTimeout вместо использования строки подключения.

Ответ 3

Тайм-аут команды и таймаут соединения - это две разные вещи.

SqlConnection.ConnectionTimeout - это время (в секундах) ожидания открытия соединения. Значение по умолчанию - 15 секунд." Это используется только при вызове SqlConnection.Open().

SqlCommand.CommandTimeout делает то, что вы хотите сделать.