views:

994

answers:

1

With regards to handling a TCP/IP connection using the TcpClient class, is there an alternative for checking whether the remote host has closed the connection other than waiting for the NetworkStream.Read method to return a 0?

+2  A: 

You can use IOControlCode.KeepAliveValues on the TcpClient.Client to guarantee that a keep-alive check is made at least on the specified interval and then check the TcpClient.Client.Connected property.

An example how to use it:

struct tcp_keepalive
{
    public int OnOff;
    public int KeepAliveTime;
    public int KeepAliveInterval;

    public unsafe byte[] Buffer
    {
        get
        {
            var buf = new byte[sizeof(tcp_keepalive)];
            fixed(void* p = &this) Marshal.Copy(new IntPtr(p), buf, 0, buf.Length);
            return buf;
        }
    }
};

static void KeepAliveTest()
{
    using(var c = new TcpClient())
    {
        c.Connect("www.google.com", 80);
        var s = c.Client;
        var ka = new tcp_keepalive();
        ka.OnOff = 1; // enable
        ka.KeepAliveTime = 1000 * 60; // 60 seconds of inactivity allowed
        ka.KeepAliveInterval = 1000; // 1 second interval on keep-alive checks (default)
        s.IOControl(IOControlCode.KeepAliveValues, ka.Buffer, null);
        var ns = c.GetStream();
        Console.WriteLine("Connected to " + s.RemoteEndPoint);
        while(true)
        {
            SocketError se;
            s.Blocking = false;
            s.Receive(new byte[0], 0, 0, SocketFlags.Peek, out se);
            s.Blocking = true;
            if(!s.Connected)
            {
                // se==SocketError.ConnectionReset||SocketError.NetworkReset if the connection was closed because of a keep-alive check
                Console.WriteLine("Socket disconnected: " + se);
                break;
            }
            // do other stuff
            if(ns.DataAvailable) ns.Read(new byte[100], 0, 100);
            else Thread.Sleep(10);
        }
    }
}
Pent Ploompuu
IOControlCode.KeepAliveValues are set using bytes as the second parameter for the Socket.IOControl Method. What is the no of bytes to use and is the value to be set in seconds or milliseconds? Can't seem to find the answers to the above mentioned questions from the following MSDN site. http://msdn.microsoft.com/en-us/library/8a3744sh.aspx
Lopper
SIO_KEEPALIVE_VALS documentation is at http://msdn.microsoft.com/en-us/library/dd877220(VS.85).aspx
Pent Ploompuu
The code is great! Thanks a lot Pent! :)
Lopper