TcpClient disconnect during async read

TDaver picture TDaver · Jun 23, 2011 · Viewed 8.1k times · Source

I have a few questions about finishing a tcp connection.

  1. A client connects to my server using Tcp, after accepting the client with listener.BeginAcceptTcpClient(ConnectionEstabilishedCallback, null);, I start to read with networkStream.BeginRead(....).
    What happens when the client disconnects while I wait for a message? (e.g. it loses power, internet, etc)
    How do I know when it happens?

  2. If after a successful read, I do some stuff, and then call networkStream.Close(); client.Close(); What will the client see? How do I terminate the connection "gracefully"?

  3. What happens if I'm waiting for a read (with BeginRead), and then (on a different thread) close the same stream?

EDIT TO ADD: I do have a ping-pong message going on between the client and server. Is that enough? If I don't receive ping, terminate my NetworkStream? surely there must be something better.

Answer

Jalal Said picture Jalal Said · Jun 23, 2011

1- If the client disconnected due to cable unplugged you will not know till the next read or write to the socket. also note that the tcpClient.Connected property value is not reliable, it's value depending on the last communication; so if the last communication were succeed then it's value is true otherwise it is false. for more information on that check this.

2- If you close the network stream and the client this is the gracefully termination of the client.

3- I don't know, give it a test.

If you aware from connection lost because of a cable unplugged or so, then to get appropriate IsConnected value you have to be aware from the connection lost during the read or write to the tcp, so you need to access the tcpclient members by potting a try-catch around its operation....

Use this IsConnected property to check if the tcpClient is connected:

public static bool IsConnected
{
    get
    {
        try
        {
            //return _tcpClient != null && _tcpClient.Client != null && _tcpClient.Client.Connected;

            if (_tcpClient != null && _tcpClient.Client != null && _tcpClient.Client.Connected)
            {

                /* As the documentation:
                    * When passing SelectMode.SelectRead as a parameter to the Poll method it will return 
                    * -either- true if Socket.Listen(Int32) has been called and a connection is pending;
                    * -or- true if data is available for reading; 
                    * -or- true if the connection has been closed, reset, or terminated; 
                    * otherwise, returns false
                    */

                // Detect if client disconnected
                if (_tcpClient.Client.Poll(0, SelectMode.SelectRead))
                {
                    byte[] buff = new byte[1];
                    if (_tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
                    {
                        // Client disconnected
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }

                return true;
            }
            else
            {
                return false;
            }
        }
        catch
        {
            return false;
        }
    }
}