2009-09-07 30 views
26

Estoy jugando con el TcpClient y estoy tratando de averiguar cómo hacer que la propiedad Connected diga falso cuando se corta una conexión.¿Cómo comprobar si la conexión de TcpClient está cerrada?

He intentado hacer

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

Pero todavía no me va a mostrar si se desconecta la TcpClient. ¿Cómo harías con un TcpClient?

Respuesta

7

Por lo que yo sé/recuerda, no hay forma de comprobar si hay un enchufe conectado que no sea leer o escribir en él.

No he usado el TcpClient en absoluto, pero la clase Socket devolverá 0 desde una llamada a Read si el extremo remoto se ha apagado correctamente. Si el extremo remoto no se cierra correctamente [Creo] que obtiene una excepción de tiempo de espera, no puede recordar el tipo lo siento.

El uso de un código como 'if(socket.Connected) { socket.Write(...) } crea una condición de carrera. Es mejor simplemente llamar al socket. Escribir y manejar las excepciones y/o desconexiones.

+0

Sí. La capa de conexión se gestionará utilizando excepciones. La IOException arrojada tiene la excepción interna establecida en una SocketException, que contiene toda la información necesaria para detectar los tiempos de espera o los sockets cerrados de forma remota. – Luca

-1

Prueba de esto, a mí me funciona

private void timer1_Tick(object sender, EventArgs e) 
    { 
     if (client.Client.Poll(0, SelectMode.SelectRead)) 
      { 
       if (!client.Connected) sConnected = false; 
       else 
       { 
        byte[] b = new byte[1]; 
        try 
        { 
         if (client.Client.Receive(b, SocketFlags.Peek) == 0) 
         { 
          // Client disconnected 
          sConnected = false; 
         } 
        } 
        catch { sConnected = false; } 
       } 
      } 
     if (!sConnected) 
     { 
      //--Basically what you want to do afterwards 
      timer1.Stop(); 
      client.Close(); 
      ReConnect(); 
     } 

    } 

i utilizado temporizador porque, quería comprobar el estado de conexión en intervalos regulares y no en un bucle con Escuchando código [sentí que estaba reduciendo la sending- proceso de recepción]

+0

tropezó con esta respuesta, solo curiosidad por qué se votó abajo? – nagates

+1

no funciona para mí, y tampoco para el que menosprecia, supongo – sotn0r

33

No recomendaría que intente escribir solo para probar el socket. Y tampoco retransmita en la propiedad Connected de .NET.

Si usted quiere saber si el punto extremo remoto todavía está activo, puede utilizar 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(); 

Ver también:
TcpConnectionInformation en MSDN
IPGlobalProperties en MSDN
Descripción de TcpState estados
Netstat en Wikipedia


Y aquí está como un método de extensión en TcpClient. respuesta

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

Esta es una respuesta increíble. La única forma de mejorarlo sería presentar la prueba como un método de extensión de Socket que devuelve el estado del socket. –

+0

Bueno. Realmente me pregunto si hay alguna manera más rápida de hacerlo, aunque –

+0

¡Gracias! Tu respuesta es la primera que funcionó para mí. He intentado con varias respuestas que usaban client.Client.Poll y no funcionaban. –

2

@ de Uriel funciona muy bien para mí, pero yo necesitaba para codificar en C++/CLI, que no era del todo trivial. Aquí está el código C++/CLI (aproximadamente equivalente), con algunas comprobaciones de robustez agregadas para una buena medida.

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

Espero que esto ayude a alguien.

2

He creado esta función y estoy trabajando para que compruebe si el cliente todavía está conectado con el servidor.

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


} 
+0

Gracias, Resuelve mi problema. – Pratikk

0

En mi caso, yo enviaba algún comando a un servidor (que se ejecuta en una máquina virtual en el mismo equipo) ya la espera de la respuesta. Sin embargo, si el servidor se detuvo inesperadamente mientras esperaba, no recibí ninguna notificación.Intenté las posibilidades propuestas por los otros carteles, pero tampoco funcionó (siempre decía que el servidor todavía estaba conectado). Para mí, lo único que se está trabajando es escribir 0 bytes con la corriente:

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

La solución de Peter Wone y Uriel es muy agradable. Pero también debe verificar el punto extremo remoto, ya que puede tener múltiples conexiones abiertas a su punto final 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; 
    } 
Cuestiones relacionadas