2010-09-01 37 views
14

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

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

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

回答

10

看起来一切都耽搁了很长时间的情况下能够得到解决更快地尝试直接socket连接这样的:

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); 
    } 
} 
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而不是使用连接字符串。

+0

ConnectionTimeout是一个只读属性 – BlueMonkMN 2010-09-01 16:20:58

+0

我在这里打一个非常奇怪的图案。当我连接到SQL Server停止的本地系统时,超时似乎正常工作。当我尝试连接到一个不存在的服务器时它似乎工作。但是,当我尝试连接到存在的服务器,但防火墙阻止SQL和/或没有安装SQL Server时,它似乎不起作用。 – BlueMonkMN 2010-09-01 16:54:23

+0

关于这个问题的一个有趣的线程在这里:http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework.adonet/topic48533.aspx。我建议实现你自己的超时机制 - 分离一个线程来尝试打开并杀死它,如果它没有在你想要的超时期限内成功。 – 2010-09-01 17:08:37

0

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

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

SqlCommand.CommandTimeout做你想做的事情。

+0

不,它不。我希望打开超时,而不是命令。 – BlueMonkMN 2010-09-01 16:18:59

+0

SqlConnection.ConnectionTimeout是你想要的 – jrummell 2010-09-02 21:24:49

+1

@GBK然后你可以设置连接字符串的超时时间。在将连接字符串传递给连接对象之前,可以使用[SqlConnectionStringBuilder](http://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnectionstringbuilder.aspx)解析和修改连接字符串。 – 2014-03-27 14:55:29