3

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.

TDaver
  • 7,164
  • 5
  • 47
  • 94
  • A great reference for working with sockets is http://tangentsoft.net/wskfaq/newbie.html#normalclose - which also elaborates on what exactly happens when a client disconnects (`NetworkStream` is an abstraction of these sockets). – C.Evenhuis Jun 23 '11 at 11:22
  • I'm new to sockets so I'd really need a dumbed-down, c# based explanation. – TDaver Jun 23 '11 at 11:54

3 Answers3

2

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;
        }
    }
}
Jalal Said
  • 15,906
  • 7
  • 45
  • 68
  • The problem with that is that the connection might have been dropped right after the `IsConnected` check. – jgauffin Jun 07 '12 at 09:31
  • true, but unlike the default `Connected` property, it just right when it get called, however for that reason `"the connection might have been dropped right after the IsConnected check"` when I faced that problem in the past, I just implement a `Timer` that checks the `IsConnected` property in a defined interval, and if failed a custom event `ConnectionChanged` or so is getting called.... – Jalal Said Jun 07 '12 at 12:27
2

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?

Different things happens for different disconnect reasons.

A graceful disconnection is detected when you receive 0 bytes from socket.EndRead. Other shutdowns will lead to SocketException for either EndRead or Send

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"?

Close will do it gracefully.

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

You'll get an exception. Either ObjectDisposedException (if you dispose the client) or IOException

jgauffin
  • 99,844
  • 45
  • 235
  • 372
-1
public class Example
{
    static NetworkStream stream;
    static TcpClient client;

    public static void Main(String[] args)

        String message = String.Empty;

        //TCP connection
 Recon: Console.WriteLine("Connecting...");
        Int32 port = 3333;
        try
        {
            client = new TcpClient("ip.ip.ip.ip", port); //Try to connect
        }
        catch
        {
            Console.WriteLine("Problem while connecting!");
            Thread.Sleep(10000); //Waiting 10s before reconnect
            goto Recon;
        }

        Console.WriteLine("Connection established!\n");

        stream = client.GetStream();

        while (true)
        {

            //Buffer
            byte[] received_bytes = new Byte[1024];
            message = "";

            Console.WriteLine("Waiting to receive message...\n");

            Int32 bytes = stream.Read(received_bytes, 0, received_bytes.Length);
            message = System.Text.Encoding.GetEncoding("iso-8859-1").GetString(received_bytes, 0, bytes);

            if (bytes == 0) //If connection abort while reading
            {
                Console.WriteLine("Connection failed!");

                //Recconecting
                goto Recon;
            }

            Console.WriteLine("Received message: " + message);
        }
    }
}
Mega
  • 557
  • 2
  • 10
  • 22
  • please don't ignore the exception object or do a loop like that. It can eat a lot of CPU for more fatal exceptions. And please use English variable names in example code. – jgauffin Jun 23 '11 at 14:20
  • It's sure that if you use this code in practice you will not ignore the exception. This is just a concept how you can detect disconnect while receiving a message. Everyone should be grateful to get a solution concept and to edit for his needs. Don't expect someone to give you code that you can use for your needs without modification, just copy-paste. About the variables it does not change you anything if **bajti** will be **bytes**. I will change this variable name in the code. – Mega Jun 24 '11 at 07:38
  • Examples should follow best practices, not some quick and dirty solution, you are after all teaching somone. And since you are writing an example it should be easy to follow. Using native variable names makes it harder. `Everyone should be grateful to get a solution concept` One may not be grateful learning bad practices and have to redo everything later on. – jgauffin Jun 07 '12 at 09:30