Parece que todos os casos que estavam causando longos atrasos poderiam ser resolvidos muito mais rapidamente tentando uma conexão direta de soquete como esta:
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);
}
}
Vou usar este código para verificar se o servidor responde na porta do SQL Server, e só tentarei abrir uma conexão se isso acontecer. Eu pensei (com base na experiência de outras pessoas) que haveria um atraso de 30 segundos mesmo nesse nível, mas recebo uma mensagem de que a máquina "recusou ativamente a conexão" imediatamente.
Editar: E se a máquina não existe, ela também me diz isso imediatamente. Não há atrasos de 30 segundos que eu possa encontrar.
Editar: As máquinas que estavam na rede, mas não estão desligadas, ainda levam 30 segundos para falhar, eu acho. As máquinas com firewall falham mais rápido, no entanto.
Editar: Aqui está o código atualizado. Eu sinto que é mais limpo fechar um soquete do que abortar um thread:
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);
}
}