我正在使用带有SqlClient.SqlConnection的SQL连接字符串,并在字符串中指定Connection Timeout = 5,但它仍然等待30秒才返回失败。如何让它放弃并快速返回?我在一个快速的本地网络上,不想等待30秒。未打开的服务器需要30秒才能失败。这只是一个快速的实用程序,它总是在这个本地网络上运行。
修改:如果我不清楚,请抱歉。我希望SqlConnection.Open更快地失败。希望这可以从我想要更快失败的服务器被关闭的事实中推断出来。
修改:似乎设置有时会失败。就像它知道服务器的IP地址,并使用TCP / IP与它通信(非本地)但不能联系该地址的SQL Server?我不确定该模式是什么,但我在本地连接SQL Server停止时没有看到问题,并且在尝试连接到不存在的服务器时我没有看到它。我尝试联系Windows 2008防火墙阻止SQL Server的服务器时看到过它。
答案 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执行您想要执行的操作。