How to check if TcpClient Connection is closed?

66,964

Solution 1

I wouldn't recommend you to try write just for testing the socket. And don't relay on .NET's Connected property either.

If you want to know if the remote end point is still active, you can use TcpConnectionInformation:

TcpClient client = new TcpClient(host, port);

IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();

if (tcpConnections != null && tcpConnections.Length > 0)
{
    TcpState stateOfConnection = tcpConnections.First().State;
    if (stateOfConnection == TcpState.Established)
    {
        // Connection is OK
    }
    else 
    {
        // No active tcp Connection to hostName:port
    }

}
client.Close();

See Also:
TcpConnectionInformation on MSDN
IPGlobalProperties on MSDN
Description of TcpState states
Netstat on Wikipedia


And here it is as an extension method on TcpClient.

public static TcpState GetState(this TcpClient tcpClient)
{
  var foo = IPGlobalProperties.GetIPGlobalProperties()
    .GetActiveTcpConnections()
    .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint));
  return foo != null ? foo.State : TcpState.Unknown;
}

Solution 2

As far as I know/remember there is no way to test if a socket is connected other than reading or writing to it.

I haven't used the TcpClient at all but the Socket class will return 0 from a call to Read if the remote end has been shutdown gracefully. If the remote end doesn't shutdown gracefully [I think] you get a timeout exception, can't remember the type sorry.

Using code like 'if(socket.Connected) { socket.Write(...) } creates a race condition. You're better off just calling socket.Write and handling the exceptions and/or disconnections.

Solution 3

The solution of Peter Wone and uriel is very nice. But you also need to check on the Remote Endpoint, since you can have multiple open connections to your Local Endpoint.

    public static TcpState GetState(this TcpClient tcpClient)
    {
        var foo = IPGlobalProperties.GetIPGlobalProperties()
          .GetActiveTcpConnections()
          .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)
                             && x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint)
          );

        return foo != null ? foo.State : TcpState.Unknown;
    }

Solution 4

I have created this function and working for me to check if client is still connected with server.

/// <summary>
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER.
/// </summary>
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns>
public bool isClientConnected()
{
    IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();

    TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();

    foreach (TcpConnectionInformation c in tcpConnections)
    {
        TcpState stateOfConnection = c.State;

        if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
        {
            if (stateOfConnection == TcpState.Established)
            {
                return true;
            }
            else
            {
                return false;
            }

        }

    }

    return false;


}

Solution 5

@uriel's answer works great for me, but I needed to code it in C++/CLI, which was not entirely trivial. Here is the (roughly equivalent) C++/CLI code, with a few robustness checks added in for good measure.

using namespace System::Net::Sockets;
using namespace System::Net::NetworkInformation;

TcpState GetTcpConnectionState(TcpClient ^ tcpClient)
{
    TcpState tcpState = TcpState::Unknown;

    if (tcpClient != nullptr)
    {
        // Get all active TCP connections
        IPGlobalProperties ^ ipProperties = IPGlobalProperties::GetIPGlobalProperties();
        array<TcpConnectionInformation^> ^ tcpConnections = ipProperties->GetActiveTcpConnections();

        if ((tcpConnections != nullptr) && (tcpConnections->Length > 0))
        {
            // Get the end points of the TCP connection in question
            EndPoint ^ localEndPoint = tcpClient->Client->LocalEndPoint;
            EndPoint ^ remoteEndPoint = tcpClient->Client->RemoteEndPoint;

            // Run through all active TCP connections to locate TCP connection in question
            for (int i = 0; i < tcpConnections->Length; i++)
            {
                if ((tcpConnections[i]->LocalEndPoint->Equals(localEndPoint)) && (tcpConnections[i]->RemoteEndPoint->Equals(remoteEndPoint)))
                {
                    // Found active TCP connection in question
                    tcpState = tcpConnections[i]->State;
                    break;
                }
            }
        }
    }

    return tcpState;
}

bool TcpConnected(TcpClient ^ tcpClient)
{
    bool bTcpConnected = false;

    if (tcpClient != nullptr)
    {
        if (GetTcpConnectionState(tcpClient) == TcpState::Established)
        {
            bTcpConnected = true;
        }
    }
    return bTcpConnected;
}

Hopefully this will help somebody.

Share:
66,964
RoboDev
Author by

RoboDev

Updated on August 20, 2020

Comments

  • RoboDev
    RoboDev over 3 years

    I'm playing around with the TcpClient and I'm trying to figure out how to make the Connected property say false when a connection is dropped.

    I tried doing

    NetworkStream ns = client.GetStream();
    ns.Write(new byte[1], 0, 0);
    

    But it still will not show me if the TcpClient is disconnected. How would you go about this using a TcpClient?

  • Luca
    Luca over 13 years
    Yeah. Socket layer shall managed using exceptions. The IOException thrown has the inner exception set to a SocketException, which contains all information required to detect timeouts or closed sockets remotely.
  • Peter Wone
    Peter Wone over 9 years
    This is an awesome answer. The only way you could improve it would be to present the test as an extension method of Socket that returns the socket state.
  • nagates
    nagates over 9 years
    stumbled across this answer, just curious why it was down voted?
  • Arsen Zahray
    Arsen Zahray over 8 years
    Nice one. I really wonder if there is any faster way to do it though
  • Blake Thingstad
    Blake Thingstad over 7 years
    Thank you! Your answer is the first that has worked for me. I have tried various answers that used client.Client.Poll and they weren't working.
  • Tom
    Tom about 7 years
    Several issues: I just tried the extension method and received the following exception: "Sequence contains more than one matching element". The first bit of code works for me, after I also added a check that tcpConnections.Length==1 (if there are several results then we have an issue - how can we know that we're looking at the right result). I.e. the use of "SingleOrDefault" seems correct to me, which means it's required in the first bit of code. Also note that in the extension method there's no check for RemoteEndPoint equality.
  • mozkomor05
    mozkomor05 about 6 years
    Use FirstOrDefault instead of SingleOrDefault
  • Pierre
    Pierre about 5 years
    I'm getting The method or operation is not implemented. at System.Net.NetworkInformation.UnixIPGlobalProperties.GetActi‌​veTcpConnections() or is it just me?
  • Wagner Pereira
    Wagner Pereira about 5 years
    change the line, .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint));
  • JasonEdinburgh
    JasonEdinburgh almost 5 years
    This doesn't detect if you disable Wifi on the server machine. Tested with Win10
  • mrid
    mrid over 4 years
    For some reason, this is always returning true