AhmadAli
AhmadAli

Reputation: 45

Determine broken connection in TCP server

I wrote a tcp server, each time a client connection accepted, the socket instance returned by Accept or EndAccept which is called handler and many other information gathered in object called TcpClientConnection, I need to determine whether a connection is connected or not at some specific interval times, the Socket.Connected property is not reliable and according to the documentation i should use the Poll method with SelectRead option to do it. with a test scenario i unplug the client cable, and wait for broken alarm which is built upon the handler.Poll(1, SelectMode.SelectRead), it should return true but never it happened.

Upvotes: 0

Views: 1679

Answers (2)

Andrew Skirrow
Andrew Skirrow

Reputation: 3451

This is a fundamentally caused by the way the TCP and IP protocols work. The only way to detect if a connection is disconnected is to send some data over the connection. The underlying TCP protocol will cause acknowledgements to be sent from the receiver back to the sender thereby allowing a broken connection to be detected.

These articles provide some more information

Do I need to heartbeat to keep a TCP connection open?

http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html

Upvotes: 3

Jan
Jan

Reputation: 1975

According to the documentation of Socket.Poll:

This method cannot detect certain kinds of connection problems, such as a broken network cable, or that the remote host was shut down ungracefully. You must attempt to send or receive data to detect these kinds of errors.

In another words - Poll is useful for checking if some data arrived and are available to your local OS networking stack. If you'd need to detect the connection issues you need to call blocking read (e.g. Socket.Receive)

You can also build a simple initialization miniprotocol to exchange some agreed 'hello' back and forth message. Here is a simplified example how you can do it:

    private bool VerifyConnection(Socket socket)
    {
        byte[] b = new byte[1];
        try
        {
            if (socket.Receive(b, 0, 1, SocketFlags.None) == 0)
                throw new SocketException(System.Convert.ToInt32(SocketError.ConnectionReset));
            socket.NoDelay = true;
            socket.Send(new byte[1] { SocketHelper.HelloByte });
            socket.NoDelay = false;
        }
        catch (Exception e)
        {
            this._logger.LogException(LogLevel.Fatal, e, "Attempt to connect (from: [{0}]), but encountered error during reading initialization message", socket.RemoteEndPoint);
            socket.TryCloseSocket(this._logger);
            return false;
        }


        if (b[0] != SocketHelper.HelloByte)
        {
            this._logger.Log(LogLevel.Fatal,
                "Attempt to connect (from: [{0}]), but incorrect initialization byte sent: [{1}], Ignoring the attempt",
                socket.RemoteEndPoint, b[0]);
            socket.TryCloseSocket(this._logger);
            return false;
        }

        return true;
    }

Upvotes: 1

Related Questions