开发者

Checking for presence of .NET remoting server - is my approach correct?

It's not possible to set a connection timeout on a .NET remoting call. Documentation occasionally refers to Tc开发者_Python百科pChannel properties that allegedly do this, but discussions and the most recent docs I've found indicate that this is not possible. One may set a timeout on the remoting call itself, but not on the initial connection attempt. You're stuck with the default 45-second timeout.

For various reasons I can't use WCF.

This causes a problem when the remoting server goes away. If I attempt to make a remoting call, I'm stuck for those 45 seconds. That's not good. I want to check for the presence of the remoting server. Pinging it with a PingTimeout is the simplest approach, but I want to check specifically for the remoting server, as opposed to just the machine being up.

After some experimentation, I've come up with this approach:

  1. Asynchronously begin a TCP socket connection to the remoting port.
  2. Wait for the connection to complete, or a timeout to expire (using a ManualResetEvent).
  3. If the connection async callback succeeded, return success. Otherwise, return failure.

This works, but I'm unsure about my use of my WaitHandle and socket. I'd also like to assure thread-safety WRT concurrent checks, which I think I've done. My code's below. Do you see any problems with my approach?

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; }
}


Your approach seems fine, but would be more inclined to wrap the socket code in a using to ensure no resource leak in IsChannelOpen function, and wrap it around the try/catch block also, as if the connection failed you'll get a nasty surprise if a socket exception occurred and your code jumps off into the woods never to be seen again.

Here is what I think should be done to robust-ify the code:

    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; }
    }


I couldn't believe .NET remoting doesn't support timeout. I found a tip in Stack Overflow question Remoting set timeout. There, somebody claims the property is "connectionTimeout", but based on my testing, it is the "timeout" property. It is working, just not to exact amount of the time you specified. Roughly, if you specify 2000 millisec, it times out at 4000 millisec. Here is my code:

   IDictionary dic = new Hashtable();
   dic["timeout"] = 2000;
   ChannelServices.RegisterChannel(new HttpChannel(dic, null, null), false);
   ...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜