2010-01-06 7 views
11

Il semble que l'utilisation de socket.Close() pour un socket tcp, ne ferme pas complètement le socket. Dans l'exemple suivant, j'essaie de me connecter à example.com au port 9999, qui n'est pas ouvert, et après un court délai, j'essaye de fermer le socket.Socket.Close ne ferme pas vraiment tcp socket? (C#)

for (int i = 0; i < 200; i++) 
    { 
    Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    sock.LingerState = new LingerOption(false, 0); 
    sock.BeginConnect("www.example.com", 9999, OnSocketConnected, sock); 
    System.Threading.Thread.Sleep(50); 
    sock.Close(); 
    } 

Mais quand je regarde à netstat après la boucle est terminée, je trouve qu'il ya beaucoup de prises entrouvertes:

TCP israel-xp:6506   www.example.com:9999 SYN_SENT 
    TCP israel-xp:6507   www.example.com:9999 SYN_SENT 
    TCP israel-xp:6508   www.example.com:9999 SYN_SENT 
    TCP israel-xp:6509   www.example.com:9999 SYN_SENT 

EDIT . Ok, un peu de contexte manquait. J'utilise beginconnect parce que je m'attends à ce que la connexion socket échoue (9999 n'est pas ouvert), et dans mon code réel, j'appelle le socket.Fermeture() une fois qu'une minuterie est définie. Sur OnSocketConnected, j'appelle EndConnect, qui déclenche une exception (en essayant d'appeler une méthode d'un objet éliminé). Mon but est d'avoir un court délai pour l'étape de connexion de socket.

Une idée de ce que je fais mal? Merci!

Répondre

14

Il fermera la partie .NET du socket. Cependant, conformément à la spécification TCP, le système d'exploitation doit maintenir les bits d'information de niveau inférieur du socket ouverts pendant un certain temps afin de détecter la retransmission, et similaires. Dans ce cas particulier, il est probable que le socket reste un peu dans l'ordre pour détecter une réponse au paquet SYN envoyé afin qu'il puisse répondre de façon plus raisonnable et ne pas mélanger la réponse avec d'autres paquets envoyés.

+2

qui a du sens, mais ne fixe pas à false devrait le résoudre? – r0u1i

+0

oh, s'attarder ne fait pas ça. Donc, il n'y a pas vraiment de moyen de faire en sorte que Windows termine le socket. – r0u1i

+1

par défaut, il restera dans l'état FIN_WAIT pendant 4 minutes avant que Windows ne le ferme vraiment. Plus intéressant encore, si vous rouvrez une autre connexion à la même destination/port, Windows va réutiliser les connexions dans FIN_WAIT qui correspondent. – Jay

10

Vous appelez *Begin*Connect - le faisant de manière asynchrone. Vous essayez probablement de fermer la socket avant même qu'elle ne soit connectée - alors quand elle se connecte, elle reste ouverte. Essayez de vous connecter de manière synchrone - ou de le fermer en OnSocketConnected afin de voir l'effet de la fermeture d'une prise véritablement connectée.

+0

Voir ma modification. J'utilise BeginConnect à dessein, et mon code actuel attend un délai avant d'appeler Close. Appeler simplement EndConnect sur une telle socket (où le port de destination n'est pas ouvert), prendra juste un * long * temps pour terminer. Ou, en d'autres termes, je souhaite que la phase de connexion du socket expire après X millisecondes (et non le nombre absurdement élevé de fenêtres millisecondes par défaut). – r0u1i

18

Par conception, vous devez toujours appeler Shutdown avant de fermer le socket.

mySocket.Shutdown(SocketShutdown.Both); 
mySocket.Close(); 

Cela désactive envoyer et recevoir sur la prise, il ne sera pas accepter des données entrantes après avoir fermé, même si le système d'exploitation a encore le contrôle.

Jon Skeet a également un point, que puisque vous ouvrez la connexion de manière asynchrone, il peut effectivement se connecter pendant que vous essayez de le fermer. Cependant, si vous appelez le Shutdown, il ne permettra pas que les informations soient reçues comme vous le faites.

Édition: Vous pouvez seulement un socket qui est déjà connecté, gardez cela à l'esprit lorsque vous écrivez votre code.

+0

+1 pour le commentaire sur la réponse de Jon Skeet. :-) –

+0

ShutDown lance une exception si le socket n'est pas encore connecté - ce qui est exactement mon scénario. – r0u1i

+0

Ensuite, vous devez utiliser OnSocketConnected pour appeler ShutDown dessus et le fermer, ou quelque chose de cette nature. –

0

Vous initialisez un nouveau socket dans chaque boucle ... avec * .close() vous fermez l'ancien et au début vous en créez un nouveau avec les mêmes paramètres que le socket précédent.

+0

oui. mais je vois beaucoup plus de sockets ouverts qu'un seul. – r0u1i

Questions connexes