Je lance un programme particulier sur Linux qui plante parfois. Si vous l'ouvrez rapidement après cela, il écoute sur le socket 49201 au lieu de 49200 comme il l'a fait la première fois. netstat révèle que 49200 est dans un état TIME_WAIT.
Existe-t-il un programme que vous pouvez exécuter pour forcer immédiatement ce socket à quitter l'état TIME_WAIT?
TIME_WAIT
sur le serveur" , passez simplement aux trois premières réponses qui évitent la question au lieu de la répondre.Réponses:
Laissez-moi élaborer. Le protocole de contrôle de transmission (TCP) est conçu pour être un protocole de transmission de données bidirectionnel, ordonné et fiable entre deux points d'extrémité (programmes). Dans ce contexte, le terme fiable signifie qu'il retransmettra les paquets s'il se perd au milieu. Le protocole TCP garantit la fiabilité en renvoyant des paquets d'accusé de réception (ACK) pour un seul paquet ou une plage de paquets reçus de l'homologue.
Ceci est identique pour les signaux de contrôle tels que demande / réponse de terminaison. La RFC 793 définit l'état TIME-WAIT comme suit:
Voir le diagramme d'état TCP suivant:
TCP est un protocole de communication bidirectionnel. Ainsi, lorsque la connexion est établie, il n'y a pas de différence entre le client et le serveur. En outre, l'un ou l'autre peut appeler la fermeture et les deux homologues doivent se mettre d'accord sur la fermeture pour fermer complètement une connexion TCP établie.
Appelons le premier à appeler les quittes en tant que rapproché actif, et l'autre à scruter le plus proche passif. Lorsque le système de fermeture actif envoie FIN, l'état passe à FIN-WAIT-1. Ensuite, il reçoit un ACK pour le FIN envoyé et l'état passe à FIN-WAIT-2. Une fois qu'il reçoit également FIN du système de rapprochement passif, le mécanisme de rapprochement actif envoie l'ACK au système FIN et l'état passe à TIME-WAIT. Si le système de rapprochement passif n'a pas reçu l'ACK du deuxième FIN, il retransmettra le paquet FIN.
Le RFC 793 définit le délai d'expiration comme étant le double de la durée de vie maximale du segment, ou 2 MSL. Depuis MSL, la durée maximale pendant laquelle un paquet peut errer sur Internet est définie sur 2 minutes, 2MSL sur 4 minutes. Puisqu’il n’ya pas d’ACK à un ACK, le système de fermeture actif ne peut rien faire, mais attendre 4 minutes s’il adhère correctement au protocole TCP / IP, juste au cas où l’émetteur passif n’aurait pas reçu l’ACK sur son FIN (en théorie). .
En réalité, les paquets manquants sont probablement rares, et très rares si tout se passe sur le réseau local ou sur un seul ordinateur.
Pour répondre à la question, comment fermer de force un socket dans TIME_WAIT?, Je vais quand même m'en tenir à ma réponse d'origine:
En pratique, je le programmerais pour qu'il ignore l'état TIME-WAIT en utilisant l'option SO_REUSEADDR mentionnée par WMR. Que fait exactement SO_REUSEADDR?
la source
/etc/init.d/networking
plate-forme (Debian?), La ligne de commande précise sera différente (parfois assez radicalement) des autres systèmes. Je conviens avec d’autres commentateurs que cela peut sembler excessif et perturber manifestement tous les services réseau non liés.Je ne sais pas si vous avez le code source de ce programme particulier que vous exécutez, mais si vous pouviez simplement définir SO_REUSEADDR via
setsockopt(2)
ce qui vous permet de vous lier à la même adresse locale même si le socket est à l'état TIME_WAIT (sauf si socket écoute activement, voirsocket(7)
).Pour plus d'informations sur l'état TIME_WAIT, voir la FAQ sur les sockets Unix .
la source
SO_REUSEADDR
ne "ferme" pas une socket. Cela vous permet simplement de réutiliser ceux qui sont déjà ouverts. Donc, la question est toujours "Comment forcer de force un socketTIME_WAIT
?"SO_REUSEADDR
laisseronsbind()
procéder; mais si vous voulez ensuite écouter cette prise, vouslisten()
reviendrezEADDRINUSE
tout de même. En d'autres termes, cette réponse peut aider le logiciel client utilisant des ports éphémères, mais ne résout pas le problème du logiciel serveur.Autant que je sache, il est impossible de fermer de force le socket en dehors de l'écriture d'un meilleur gestionnaire de signal dans votre programme, mais il existe un fichier / proc qui contrôle la durée du délai d'attente. Le fichier est
et vous pouvez définir le délai d'attente à 1 seconde en procédant comme suit:
Cependant, cette page contient un avertissement sur les problèmes de fiabilité possibles lors de la définition de cette variable.
Il y a aussi un fichier lié
qui contrôle si les sockets TIME_WAIT peuvent être réutilisés (probablement sans aucun délai).
Incidemment, la documentation du noyau vous avertit de ne changer aucune de ces valeurs sans «conseils / demandes d'experts techniques». Ce que je ne suis pas.
Le programme doit avoir été écrit pour tenter une liaison vers le port 49200, puis incrémenter de 1 si le port est déjà utilisé. Par conséquent, si vous avez le contrôle du code source, vous pouvez modifier ce comportement afin d'attendre quelques secondes et essayer à nouveau sur le même port, au lieu de l'incrémenter.
la source
1
fonctionne pour les connexions futures, mais qu'en est-il des connexions actuelles déjà ouvertes?En fait, il existe un moyen de tuer une connexion - killcx . Ils prétendent que cela fonctionne dans n’importe quel état de la connexion (que je n’ai pas vérifié). Vous devez connaître l’interface où la communication a lieu, mais il semble que eth0 soit utilisé par défaut.
UPDATE: une autre solution est le cutter qui vient dans les dépôts de certaines distributions linux.
la source
Une autre option consiste à utiliser l'option SO_LINGER avec un délai d'expiration égal à 0. De cette manière, lorsque vous fermez le socket est forcément fermé, l'envoi d'un RST au lieu d'entrer dans le comportement de fermeture FIN / ACK. Cela évitera l'état TIME_WAIT et sera peut-être plus approprié pour certaines utilisations.
la source
Une autre solution serait de disposer d’un logiciel de transfert de proxy ou de port fiable qui écoute sur le port 49200, puis de transférer la connexion vers l’une des instances de votre programme moins fiable utilisant différents ports ... HAPROXY me vient à l’esprit.
Le port sur lequel vous vous connectez est assez élevé. Vous pouvez essayer d’utiliser un inutilisé juste au-dessus de la plage 0-1024. Votre système est moins susceptible d’utiliser un numéro de port inférieur en tant que port éphémère.
la source
TIME_WAIT est le problème le plus courant dans l’architecture serveur de programmation par socket. Attendre quelques secondes en essayant périodiquement est la meilleure solution. Pour les applications en temps réel, le serveur doit être installé immédiatement. Il existe une option SO_REUSEADDR pour elles.
la source