2009-11-20 6 views
8

J'ai un objet TcpClient qui envoie des données au serveur, en utilisant son NetworkStream.Write() sous-jacent. cet effet, j'ai:Quelle est la manière correcte de fermer une connexion TCP?

TcpClient server = new TcpClient(serverName, 50001); 

/* ... */ 

NetworkStream stream = server.GetStream(); 

Maintenant, quand un bouton est pressé, la connexion doit fermer. Quelle est la bonne façon de fermer la connexion? Les documents MSDN indiquent que la fermeture du TcpClient (avec .Close()) ne ferme en fait pas le socket, seulement les ressources TcpClient (c'est du moins la façon dont j'ai compris les docs). Donc, le code suivant fermerait-il correctement la connexion?

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

Est-ce suffisant, ou devrais-je vérifier d'abord (en quelque sorte) si le flux (ou serveur) peuvent être fermés (si la connexion est à moitié ouverte ou quelque chose) ...

Encore plus , NetworkStream.Close() MSDN documents indique qu'il libère des ressources (même sockets), donc peut-être la fermeture du flux suffirait, que j'empêche d'utiliser le TcpClient après ce point.

Quelle est la bonne approche?

Répondre

6

Comme the docs disent:

appel à cette méthode finira par entraîner la fermeture du socket associé et fermera également NetworkStream associé qui est utilisé pour envoyer et recevoir des données si l'on a été créé.

Alors server.Close(); suffira.

Fermer le NetworkStream en premier ne fera jamais mal.

Soit dit en passant, si vous arrive d'utiliser la TcpClient dans une seule méthode, l'envelopper dans une déclaration using() afin que vous êtes sûr Dispose() (équivalent à Close()) est appelé, même si des exceptions sont levées, etc.

+1

Je suppose que je faisais confiance IntelliSense trop. Le popup pour le TcpClient.Close() indique ceci: "Dispose cette instance de System.Net.Sockets.TcpClient sans fermer la connexion sous-jacente." Chose étrange. Merci pour la réponse si. –

+0

En effet, c'est ce que les docs 3.0 (http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.close(VS.85).aspx) disent dans la première phrase ... mais alors la troisième phrase dit qu'elle * ferme * Socket et NetworkStream. Les docs 3.5 (que j'ai liés plus tôt) sont cohérents. Je soupçonne que la ligne dans les docs 3.0 était une erreur. – Joren

0

Vous avez raison de fermer le flux puis le serveur. Cela devrait aboutir à ce que toutes les sockets soient fermées avec succès au fil du temps, comme l'indique la documentation. Cependant, plusieurs bugs de grattage de la tête m'ont enseigné la leçon importante au fil du temps:

N'oubliez pas de rincer!

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

Vous perdrez souvent des données que vous pensiez avoir éventuellement envoyées. Cela permet également de s'assurer que le flux doit être vide et inactif lorsque vous le fermez.

+9

À partir des documents sur NetworkStream: «La méthode Flush implémente la méthode Stream.Flush, mais comme NetworkStream n'est pas mis en mémoire tampon, elle n'a aucun effet sur les flux réseau.Appeler la méthode Flush ne génère pas d'exception. Donc, cela n'a pas vraiment d'importance si vous videz le flux ou non. – Joren

3

Je vais associer une connexion TCP à une socket.

En général, la procédure est comme suit: 1. Terminer l'envoi de données 2. Appel Socket.Shutdown avec le paramètre SocketShutdown.Send 3. Boucle sur réception jusqu'à ce qu'il retourne 0 ou échoue avec une exception 4.Quasi-()

Voici un petit échantillon dans le code pseudo qui est très similaire à 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(); 
} 

Si première et troisième étapes sont sautées - la perte de données peut se produire.

Taken de How to close TCP socket

+0

Juste ce dont j'avais besoin, merci! Dans mon cas, les autres réponses ne fonctionnaient pas. C'est peut-être parce que je ne lisais pas toutes les données disponibles du client dans certains cas (dans certains cas, je retournerais une erreur avant de lire toutes les données, puis fermerais la connexion). Avec cette méthode, il démarre l'arrêt, puis lit toutes les autres données en attente. – eselk

Questions connexes