2009-09-07 5 views
26

Sto giocando con il TcpClient e sto cercando di capire come rendere falsa la proprietà Connected quando una connessione viene interrotta.Come verificare se la connessione TcpClient è chiusa?

Ho provato a fare

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

Ma ancora non mi mostrerà se il TcpClient è scollegato. Come andresti su questo usando un TcpClient?

risposta

7

Per quanto ne so/ricordo, non c'è modo di testare se un socket è collegato oltre a leggere o scrivere su di esso.

Non ho usato affatto il TcpClient ma la classe Socket restituirà 0 da una chiamata a Read se il terminale remoto è stato arrestato correttamente. Se il terminale remoto non si spegne correttamente [credo] si ottiene un'eccezione di timeout, non ricordo il tipo mi dispiace.

L'utilizzo di codice come 'if(socket.Connected) { socket.Write(...) } crea una condizione di competizione. Stai meglio chiamando il socket. Scrittura e gestione delle eccezioni e/o disconnessioni.

+0

Sì. Lo strato di socket deve essere gestito utilizzando le eccezioni. L'eccezione IOException ha l'eccezione interna impostata su SocketException, che contiene tutte le informazioni richieste per rilevare timeout o socket chiusi in remoto. – Luca

-1

Prova questo, per me funziona

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

    } 

ho usato timer perché, ho voluto verificare lo stato della connessione a intervalli regolari e non in un ciclo con ascolto codice [ho sentito che stava rallentando l'sending- processo di ricezione]

+0

è incappato in questa risposta, solo curioso di sapere perché non è stato votato? – nagates

+1

non funziona per me, e nemmeno per il downvoter credo che – sotn0r

33

Non mi consiglia di provare a scrivere solo per testare la presa. E non inoltrare nemmeno sulla proprietà Connected di .NET.

Se vuoi sapere se il punto finale remoto è ancora attivo, è possibile utilizzare 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(); 

Vedere anche:
TcpConnectionInformation su MSDN
IPGlobalProperties su MSDN
descrizione TcpState stati
Netstat on Wikipedia


E qui è come un metodo di estensione su 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; 
} 
+2

Questa è una risposta fantastica. L'unico modo per migliorarlo sarebbe presentare il test come metodo di estensione di Socket che restituisce lo stato del socket. –

+0

Bello. Mi chiedo davvero se c'è un modo più veloce per farlo anche se –

+0

Grazie! La tua risposta è la prima che ha funzionato per me. Ho provato varie risposte che utilizzavano client.Client.Poll e non funzionavano. –

2

@ La risposta di uriel funziona benissimo per me, ma avevo bisogno di codificarlo in C++/CLI, che non era del tutto banale. Ecco il codice (più o meno equivalente) C++/CLI, con alcune verifiche di robustezza aggiunte per buona misura.

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

Speriamo che questo possa aiutare qualcuno.

2

Ho creato questa funzione e sto lavorando per verificare se il client è ancora connesso al 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; 


} 
+0

Grazie, risolve il mio problema. – Pratikk

0

Nel mio caso, mi è stato l'invio di alcuni comandi a un server (in esecuzione in una macchina virtuale sullo stesso computer) e di attesa per la risposta. Tuttavia, se il server si è fermato inaspettatamente durante l'attesa, non ho ricevuto alcuna notifica.Ho provato le possibilità proposte dagli altri poster, ma nessuno dei due ha funzionato (ha sempre detto che il server è ancora connesso). Per me, l'unica cosa che sta lavorando è quello di scrivere 0 byte, verso la corrente

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 soluzione di Peter Wone e Uriel è molto bello. Ma devi anche controllare l'Endpoint remoto, dal momento che puoi avere più connessioni aperte al tuo Endpoint locale.

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