代码之家  ›  专栏  ›  技术社区  ›  BlueMonkMN

如何使sqlconnection超时更快

  •  14
  • BlueMonkMN  · 技术社区  · 14 年前

    我正在将SQL连接字符串与sqlclient.sql connection一起使用,并在该字符串中指定连接超时值=5,但它仍然会在返回失败之前等待30秒。我怎样才能让它放弃并更快地回来呢?我在一个快速的本地网络上,不想等待30秒。未打开的服务器需要30秒才能失败。这只是一个快速实用程序,将始终运行在这个本地网络上。

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

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

    3 回复  |  直到 14 年前
        1
  •  11
  •   BlueMonkMN    14 年前

    看来所有造成长时间延误的案件都能解决 许多的 更快速地尝试这样的直接套接字连接:

    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
  •  3
  •   Daniel Renshaw    14 年前

    更新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 而不是使用连接字符串。

        3
  •  0
  •   Justin Dearing    14 年前

    命令超时和连接超时是两个不同的东西。

    SqlConnection.ConnectionTimeout 是“等待连接打开的时间(秒)。默认值为15秒。”仅在调用sqlconnection.open()时使用。

    sqlcommand.commandTimeout执行您想要执行的操作。