2009-11-20 7 views
8

Ho un oggetto TcpClient che invia alcuni dati al server, utilizzando il suo NetworkStream.Write() sottostante. Perciò, ho:Qual è il modo corretto per chiudere una connessione TCP

TcpClient server = new TcpClient(serverName, 50001); 

/* ... */ 

NetworkStream stream = server.GetStream(); 

Ora, quando si preme un tasto, la connessione deve chiudere. Qual è il modo giusto per chiudere la connessione? I documenti MSDN dicono che chiudere il TcpClient (con .Close()) non chiude di fatto il socket, ma solo le risorse di TcpClient (almeno così ho capito i documenti).

Quindi, farebbe il prossimo codice chiudere correttamente la connessione?

stream.Close(); 
server.Close(); 

Basta questo, o dovrei primo controllo (in qualche modo) se il flusso (o server) possono essere chiuse (nel caso in cui la connessione è semiaperta o qualcosa del genere) ...

Ancora più , NetworkStream.Close() MSDN doc afferma che rilascia risorse (anche socket), quindi forse chiudere il flusso sarebbe sufficiente, supponendo che prevedo di usare il TcpClient dopo quel punto.

Qual è l'approccio giusto?

risposta

6

Come the docs dicono:

chiamata a questo metodo finirà per determinare la chiusura del socket associato e sarà anche chiudere il NetworkStream associato che viene utilizzato per inviare e ricevere dati se uno è stato creato.

Quindi server.Close(); sarà sufficiente.

Chiudere il NetworkStream non farà mai male all'inizio.

A proposito, se vi capita di essere utilizzando il TcpClient in un solo metodo, avvolgerlo in un comunicato using() in modo che si è sicuri Dispose() (equivalente a Close()) viene chiamato su di esso, anche se eccezioni sono gettati ecc

+1

Credo che mi fidavo di IntelliSense troppo. Il popup per TcpClient.Close() afferma questo: "Disporre questa istanza System.Net.Sockets.TcpClient senza chiudere la connessione sottostante." Cosa strana. Grazie per la risposta però. –

+0

Infatti, questo è ciò che i 3.0 documenti (http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.close(VS.85).aspx) dicono nella prima frase ... ma poi la terza frase dice che * fa * chiude Socket e NetworkStream. I 3.5 documenti (che ho collegato in precedenza) sono coerenti. Sospetto che la riga nei documenti 3.0 sia stata un errore. – Joren

0

Hai ragione nel chiudere lo stream quindi il server. Ciò dovrebbe comportare la chiusura di tutti i socket nel tempo, come afferma la documentazione. Tuttavia, diversi bug di graffio della testa mi hanno insegnato l'importante lezione nel tempo:

Non dimenticare di lavare!

stream.Flush(); 
stream.Close(); 
server.Close(); 

Spesso si perderanno alcuni dati che si pensava di aver inviato diversamente. Questo aiuta anche a garantire che lo stream sia vuoto e inattivo quando lo chiudi.

+9

Dai documenti su NetworkStream: "Il metodo Flush implementa il metodo Stream.Flush, tuttavia, poiché NetworkStream non è memorizzato nel buffer, non ha alcun effetto sui flussi di rete. Chiamare il metodo Flush non genera un'eccezione." Quindi non importa se svuoti il ​​flusso o no. – Joren

3

Assocerò una connessione TCP a un socket.

In generale, la procedura è simile a questo: 1. Finish invio dei dati 2. chiamata Socket.Shutdown con il parametro SocketShutdown.Send 3. Loop Ricevi fino a quando non restituisce 0 o non riesce con un'eccezione 4.Chiamare Close()

Ecco un piccolo campione in pseudo-codice che è molto simile a C# :)

void CloseConnection(Socket socket) 
{ 
    socket.Send(/*last data of the connection*/); 
    socket.Shutdown(SocketShutdown.Send); 

    try 
    { 
     int read = 0; 
     while((read = socket.Receive(/*application data buffers*/)) > 0) 
     {} 
    } 
    catch 
    { 
     //ignore 
    } 
    socket.Close(); 
} 

Se si saltano prima e la terza passi - la perdita di dati può accadere.

Tratto da How to close TCP socket

+0

Proprio quello di cui avevo bisogno, grazie! Nel mio caso le altre risposte non funzionavano. Potrebbe essere perché in alcuni casi non stavo leggendo tutti i dati disponibili dal client (in alcuni casi restituirei un errore prima di leggere tutti i dati, quindi chiudere la connessione). Con questo metodo, avvia lo spegnimento, quindi legge anche altri dati di attesa. – eselk