web-dev-qa-db-fra.com

Comment vérifier si la connexion TcpClient est fermée?

Je joue avec le TcpClient et j'essaie de comprendre comment faire en sorte que la propriété Connected dise false lorsqu'une connexion est interrompue.

J'ai essayé de faire

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

Mais il ne me montrera toujours pas si le TcpClient est déconnecté. Comment procéderiez-vous en utilisant un TcpClient?

29
Superdumbell

Je ne vous recommanderais pas d'essayer d'écrire juste pour tester le socket. Et ne relayez pas non plus sur la propriété Connected de .NET.

Si vous voulez savoir si le point de terminaison distant est toujours actif, vous pouvez utiliser 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();

Voir également:
TcpConnectionInformation sur MSDN
IPGlobalProperties sur MSDN
Description des états TcpState
Netstat sur Wikipedia


Et ici, c'est comme une méthode d'extension sur 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;
}
41
uriel

Pour autant que je sache/me souviens, il n'y a aucun moyen de tester si une prise est connectée autre que la lecture ou l'écriture.

Je n'ai pas utilisé du tout TcpClient, mais la classe Socket renverra 0 d'un appel à Read si l'extrémité distante a été arrêtée correctement. Si l'extrémité distante ne s'arrête pas correctement [je pense] vous obtenez une exception de délai d'attente, je ne me souviens pas du type désolé.

L'utilisation de code comme 'if(socket.Connected) { socket.Write(...) } crée une condition de concurrence critique. Il vaut mieux appeler simplement socket.Écrivez et gérez les exceptions et/ou les déconnexions.

7
Kepboy

J'ai créé cette fonction et travaille pour moi pour vérifier si le client est toujours connecté au serveur.

/// <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;


}
2
user391318

La solution de Peter Wine et uriel est très sympa. Mais vous devez également vérifier le point de terminaison distant, car vous pouvez avoir plusieurs connexions ouvertes à votre point de terminaison local.

    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;
    }
2
frankhommers

La réponse de @ uriel fonctionne très bien pour moi, mais je devais la coder en C++/CLI, ce qui n'était pas tout à fait trivial. Voici le code C++/CLI (à peu près équivalent), avec quelques vérifications de robustesse ajoutées pour faire bonne mesure.

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;
}

J'espère que cela aidera quelqu'un.

1
Rawk

Dans mon cas, j'envoyais une commande à un serveur (fonctionnant sur une machine virtuelle sur le même ordinateur) et j'attendais la réponse. Cependant, si le serveur s'est arrêté de manière inattendue en attendant, je n'ai reçu aucune notification. J'ai essayé les possibilités proposées par les autres affiches, mais aucune n'a fonctionné (il a toujours dit que le serveur est toujours connecté). Pour moi, la seule chose qui fonctionne est d'écrire 0 octet dans le flux:

var client = new TcpClient();
//... open the client

var stream = client.GetStream();

//... send something to the client

byte[] empty = { 0 };
//wait for response from server
while (client.Available == 0)
{
    //throws a SocketException if the connection is closed by the server
    stream.Write(empty, 0, 0);
    Thread.Sleep(10);
}
0
LionAM