如何使SqlConnection超时更快

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

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

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

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

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我建议滚动你自己的超时。 像这样的东西:

 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)); result = manualResetEvent.WaitOne(timeoutInSeconds*1000); if (!result) { thread.Abort(); } sqlConnection.Close(); } return result; } private static void TryOpen(object input) { Tuple parameters = (Tuple)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而不是使用连接字符串。

命令超时和连接超时是两个不同的事情。

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

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