如何使SqlConnection超时更快

时间:2010-09-01 14:51:18

标签: c# .net sql-server sql-server-2005

我正在使用带有SqlClient.SqlConnection的SQL连接字符串,并在字符串中指定Connection Timeout = 5,但它仍然等待30秒才返回失败。如何让它放弃并快速返回?我在一个快速的本地网络上,不想等待30秒。未打开的服务器需要30秒才能失败。这只是一个快速的实用程序,它总是在这个本地网络上运行。

修改:如果我不清楚,请抱歉。我希望SqlConnection.Open更快地失败。希望这可以从我想要更快失败的服务器被关闭的事实中推断出来。

修改:似乎设置有时会失败。就像它知道服务器的IP地址,并使用TCP / IP与它通信(非本地)但不能联系该地址的SQL Server?我不确定该模式是什么,但我在本地连接SQL Server停止时没有看到问题,并且在尝试连接到不存在的服务器时我没有看到它。我尝试联系Windows 2008防火墙阻止SQL Server的服务器时看到过它。

3 个答案:

答案 0 :(得分:11)

通过尝试像这样的直接套接字连接,看起来导致长时间延迟的所有情况都可以更快地解决

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

答案 1 :(得分:3)

更新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值。这是针对SQL Server 2008 R2的.NET 4。不可否认,这是一个本地主机连接可能会产生不同的结果,但这意味着我无法复制问题。

我只能建议您在网络环境中尝试类似的代码块,看看是否继续看到超时。

旧(不正确)答案 我错误地认为ConnectionTimeout属性是可设置的,但事实并非如此。

尝试设置SqlConnection.ConnectionTimeout而不是使用连接字符串。

答案 2 :(得分:0)

命令超时和连接超时是两回事。

SqlConnection.ConnectionTimeout是“等待连接打开的时间(以秒为单位)。默认值为15秒。”这只在您调用SqlConnection.Open()时使用。

SqlCommand.CommandTimeout执行您想要执行的操作。