2009-12-10 1 views
2

Невозможно установить время ожидания соединения на удаленном вызове .NET. Документация иногда относится к TcpChannel свойствам, которые предположительно делают это, но discussions и последние docs, которые я нашел, показывают, что это невозможно. Можно установить тайм-аут на самом удаленном вызове, но не на попытке первоначального подключения. Вы застряли с 45-секундным таймаутом по умолчанию.Проверка наличия сервера удаленной работы .NET - мой подход правильный?

По различным причинам я не могу использовать WCF.

Это вызывает проблему, когда удаленный сервер уходит. Если я попытаюсь сделать удаленный вызов, я застрял в течение этих 45 секунд. Это не хорошо. Я хочу проверить наличие удаленного сервера. Пинирование его с помощью PingTimeout - это самый простой подход, но я хочу специально проверить сервер удаленного управления, а не только машину.

После нескольких экспериментов я придумал с этим подходом:

  1. Асинхронными начать соединение TCP сокет к порту удаленного взаимодействия.
  2. Ждите подключения, или истечет время ожидания (с использованием ManualResetEvent).
  3. Если соединение асинхронный обратный вызов преуспел, верните успех. В противном случае, возврат отказа.

Это работает, но я не уверен в своем использовании своего WaitHandle и сокета. Я также хотел бы обеспечить параллельные проверки безопасности WRT с потоками, которые, как я думаю, я сделал. Мой код ниже. Вы видите какие-то проблемы с моим подходом?

private static bool IsChannelOpen(string ip, int port, int timeout) 
{ 
    IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), port); 
    Socket client = new Socket(endpoint.AddressFamily, 
       SocketType.Stream, ProtocolType.Tcp); 
    SocketTestData data = new SocketTestData() 
       { Socket = client, ConnectDone = new ManualResetEvent(false) }; 
    IAsyncResult ar = client.BeginConnect 
       (endpoint, new AsyncCallback(TestConnectionCallback), data); 

    // wait for connection success as signaled from callback, or timeout 
    data.ConnectDone.WaitOne(timeout); 
    client.Close(); 
    return data.Connected; 
} 

private static void TestConnectionCallback(IAsyncResult ar) 
{ 
    SocketTestData data = (SocketTestData)ar.AsyncState; 
    data.Connected = data.Socket.Connected; 
    if (data.Socket.Connected) 
    { 
     data.Socket.EndConnect(ar); 
    } 
    data.ConnectDone.Set(); // signal completion 
} 

public class SocketTestData 
{ 
    public Socket Socket { get; set; } 
    public ManualResetEvent ConnectDone { get; set; } 
    public bool Connected { get; set; } 
} 
+1

Я всегда ненавидел это о Remoting. –

ответ

4

Ваш подход кажется хорошо, но было бы более склонны обернуть код сокета в с помощью чтобы убедиться в отсутствии утечки ресурсов в IsChannelOpen функции, и обернуть его вокруг/поймать блока Попробуйте также, как если бы соединение не получилось, вы получите неприятный сюрприз, если возникло исключение сокета, и ваш код выскочит в лес, который больше не будет видно.

Вот что я думаю, что должно быть сделано для надежной-римента код:

private static bool IsChannelOpen(string ipAddress, int port, int timeout) 
    { 
     IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); 
     SocketTestData data; 
     try 
     { 
      using (Socket client = new Socket(endpoint.AddressFamily, 
         SocketType.Stream, ProtocolType.Tcp)) 
      { 

       data = new SocketTestData() { Socket = client, ConnectDone = new ManualResetEvent(false) }; 
       IAsyncResult ar = client.BeginConnect 
          (endpoint, new AsyncCallback(TestConnectionCallback), data); 

       // wait for connection success as signaled from callback, or timeout 
       data.ConnectDone.WaitOne(timeout); 
      } 
     } 
     catch (System.Net.Sockets.SocketException sockEx) 
     { 
     } 
     catch (System.Exception ex) 
     { 
     } 
     return data.Connected; 
    } 

    private static void TestConnectionCallback(IAsyncResult ar) 
    { 
     SocketTestData data = (SocketTestData)ar.AsyncState; 
     data.Connected = data.Socket.Connected; 
     data.Socket.EndConnect(ar); 
     data.ConnectDone.Set(); // Signal completion 
    } 

    public class SocketTestData 
    { 
     public Socket Socket { get; set; } 
     public ManualResetEvent ConnectDone { get; set; } 
     public bool Connected { get; set; } 
    } 
+0

@Tom: Отличные предложения, спасибо. Я добавил блок 'using'. Я не думаю, что ** Мне нужен блок try/catch, поскольку это исключение выбрано из синхронного вызова в IsChannelOpen, и я могу распространять исключение. Одна из моих предыдущих попыток имела безусловный вызов «EndConnect», но это не удается при сбое соединения, с SocketException («Никакое соединение не может быть сделано, потому что целевая машина активно отказала ему»). Вот почему я добавил условие, и часть того, почему я задал этот вопрос. :-) –

+0

Хммм ... 'System.Net.Sockets.Socket' не реализует' Dispose'. try/catch/наконец-то это ... –

+0

Интересно ... в VS 2008, я могу использовать сокет в выражении using (.NET Framework 3.5). Не подумал бы об этом в VS 2005 (т. Е. .NET Framework 2) – t0mm13b

2

Я не мог поверить .NET Remoting не поддерживает тайм-аут. Я нашел отзыв в Stack Overflow question Remoting set timeout. Там кто-то утверждает, что свойство «connectionTimeout», но на основании моего тестирования это свойство «timeout». Он работает, просто не точно укажите время, которое вы указали. Грубо говоря, если вы укажете 2000 миллисекунд, время истечет через 4000 миллисекунд. Вот мой код:

IDictionary dic = new Hashtable(); 
    dic["timeout"] = 2000; 
    ChannelServices.RegisterChannel(new HttpChannel(dic, null, null), false); 
    ... 
Смежные вопросы