Comment puis-je tuer un processus qui est mort mais en écoutant?

48

Je développe une application qui écoute sur le port 3000. Apparemment, le port écoute toujours car, à chaque démarrage, il ne peut pas créer d'écouteur (C #, TcpListener, mais ce n'est pas pertinent), car le port est déjà pris.

L'application n'existe pas dans le Gestionnaire des tâches. J'ai donc essayé de trouver son PID et de le tuer, ce qui a conduit à ce résultat intéressant:

C:\Users\username>netstat -o -n -a | findstr 0.0:3000
   TCP    0.0.0.0:3000           0.0.0.0:0              LISTENING       3116

C:\Users\username>taskkill /F /PID 3116
ERROR: The process "3116" not found.

Je n'avais jamais vu ce comportement auparavant et pensais que c'était assez intéressant pour voir si quelqu'un avait une solution.

UPDATE: J'ai démarré Process Explorer et fait une recherche sur 3000 et constaté ceci:

<Non-existent Process>(3000): 5552

J'ai fait un clic droit dessus et choisi "Fermer le manche". Ce n'est plus dans Process Explorer, mais apparaît toujours dans netstat et empêche toujours l'application de démarrer l'écouteur.

UPDATE 2: Trouvé TCPView pour Windows qui montre le processus comme "<non-existent>". Comme avec CurrPorts, rien ne se passe lorsque j'essaie de fermer la connexion dans cet outil.

Srekel
la source
un peu de guérir la maladie en tuant le patient, mais cela s'arrête-t-il si vous redémarrez l'ordinateur?
Xantec
2
En fait, il était suffisant de se déconnecter et de revenir, mais j'ai maintenant réussi à le reproduire et j'aimerais donc toujours trouver une meilleure solution ...
Srekel
Vérifiez si l'un des programmes répertoriés ci - dessous aide
Sathyajith Bhat
1
Avec la version actuelle de TCPView 3.05, "Fermer la connexion" du menu contextuel du processus <non-exsitent> a correctement fermé la connexion dans mon cas et libéré le port.
Ventzy Kunev
1
Voir aussi serverfault.com/questions/181015/…
rogerdpack

Réponses:

13

Pour éviter des attentes interminables sur le socket, votre programme doit utiliser la fonction setsockopt avec les paramètres SO_REUSEADDR et SO_RCVTIMEO:

SO_REUSEADDR : Allows the socket to be bound to an address that is already in use.
SO_RCVTIMEO : Sets the timeout, in milliseconds, for blocking receive calls. 
harrymc
la source
1
Est-ce que cela a aidé quelqu'un avec ce problème particulier (prise d'écoute par un processus mort)?
rustyx
12

Nous avons eu le même problème et avons utilisé Process Explorer de Microsoft Sysinternals pour rechercher l'ID de processus qui n'existait plus.

Il s'avère que le processus a été référencé par plusieurs processus DrWatson. Tuer ces processus a libéré le port. DrWatson est utilisé pour envoyer des vidages de mémoire à Microsoft, ce qui prenait plusieurs heures, car le processus à l'origine du crash avait plusieurs dizaines de Go de mémoire à la fois.

David
la source
7

Je pense que vous devriez essayer CurrPorts

CurrPorts est un logiciel de surveillance réseau qui affiche la liste de tous les ports TCP / IP et UDP actuellement ouverts sur votre ordinateur local. Pour chaque port de la liste, des informations sur le processus qui a ouvert le port sont également affichées, y compris le nom du processus, le chemin complet du processus, les informations de version du processus (nom du produit, description du fichier, etc.), l'heure à laquelle le processus a été créé et l'utilisateur qui l'a créé.

De plus, CurrPorts vous permet de fermer les connexions TCP non désirées, de tuer le processus qui a ouvert les ports et d'enregistrer les informations sur les ports TCP / UDP dans un fichier HTML, un fichier XML ou un fichier texte délimité par des tabulations.

CurrPorts marque également automatiquement en rose les ports TCP / UDP suspects appartenant à des applications non identifiées (Applications sans informations de version et icônes)

texte alternatif

Sathyajith Bhat
la source
4
Il apparaît dans la liste sous le nom de processus "Système". J'ai essayé de cliquer avec le bouton droit de la souris pour forcer la fermeture du port, mais rien ne se passe.
Srekel
7

Le problème probable est que votre processus a démarré un autre processus (enfant) qui a hérité du descripteur de socket et qu'il est toujours en cours d'exécution.

Il existe différentes manières d'éviter cela, par exemple: ProcessStartInfo.UseShellExecute = true;

Nick Westgate
la source
1
Merci, c'était un bon. J'appelais en subprocess.call(..., cwd=..., shell=True)tant que lanceur d'application sur un serveur Web python et il s'est avéré que je devais tuer tous ces processus enfants pour libérer le socket. La chose étrange est que j'utilise shell = True. Cela m'a agacé pendant des siècles.
Daniel F
Je ne pense pas que l'utilisation d'un shell entraîne ce comportement. Si vous souhaitez mettre fin à tous les processus enfants lorsque le parent meurt, je pense que la méthode correcte consiste à créer un objet Job avec l' indicateur JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE , à ajouter chaque processus enfant à l'aide de AssignProcessToJobObject et à autoriser la fermeture naturelle du descripteur lors de la fermeture du processus parent.
Qris
1

Pouvez-vous voir le processus dans Process Explorer ? Si oui que vous pouvez le tuer à partir de là, mais seulement après avoir enquêté sur ce que c'est réellement (vous pouvez voir toutes les dll chargées dans le processus)

Jakub Konecki
la source
1

Essayez de lancer un drapeau '-b' sur votre commande netstat. Il vous dira le nom de l'exécutable qui utilise le port. Puis trouvez ce proc dans le gestionnaire de tâches et tuez-le là. Si cela ne fonctionne pas, affichez l'exécutable qui maintient le port ouvert.

Ge3ng
la source
Je ne peux pas le reproduire pour le moment, mais je suis à peu près sûr que, puisque toutes les autres tentatives (et tous les outils) permettant de trouver le nom du processus ont échoué, Netstat n'aurait pas pu le faire non plus.
Srekel
1

Il faut mentionner le terme s'attarder ici.

Les détails peuvent être trouvés à http://msdn.microsoft.com/en-us/library/ms739165.aspx

En bref: Une option indique au système de socket de garder un socket ouvert même après sa fermeture si des données non envoyées sont présentes.

Dans votre application C #, vous pouvez spécifier les options associées via Socket.SetSocketOption: http://msdn.microsoft.com/en-us/library/1011kecd.aspx

Puisque tout ce qui est mentionné concerne l'envoi et les clients, mais que nous avions des problèmes similaires au travail, certaines recherches ultérieures ont révélé qu'il était possible de spécifier l'option de linger pour les écouteurs, comme indiqué dans l'exemple ci-dessous: http://msdn.microsoft.com /library/system.net.sockets.tcplistener.server.aspx

Certains collègues ont parlé des ports détenus par le système d'exploitation après une fermeture / fermeture d'application pendant environ deux minutes. Cela étant, il serait intéressant de savoir si le port est toujours tenu après un certain temps.

Andreas
la source
Les ports ont été maintenus ouverts beaucoup plus longtemps que cela (je ne me rappelle pas combien de temps, mais peut-être jusqu'à une heure avant d'abandonner et de redémarrer).
Srekel
Je ne suis pas sûr que l'option Linger soit pertinente dans ce cas particulier, car il semble qu'elle ne spécifie que ce qui est censé se passer après un appel à CloseSocket. Depuis que je tue l'application, je doute que cette fonction s'appelle (?).
Srekel
1

Je rencontre aussi ce problème. Finalement j'ai trouvé ma raison. C'est causé par le processus principal appelé un processus enfant par popen dans c / c ++. Mais le processus principal se bloque / se ferme avant d'appeler pclose. Ensuite, le port traitera le processus principal toujours actif et l'écoutera toujours.

camion.lee
la source
1
J'ai trouvé cette réponse utile à ServerFault: serverfault.com/a/273727/8856
Harriv
1

J'ai eu le même problème avec xdebug, il a laissé le port 9000 ouvert.

J'ai réussi à fermer avec cmd en utilisant "taskkill / pid xxxx".

Le pid du processus utilisant le port peut être récupéré avec "netstat -o".

Ma configuration était win 7 home premium.

Christoforos
la source
1

J'ai eu le même problème et résolu par:

  • trouver le PID avec netstat -o
  • Tuez-le avec processus xp

Il est intéressant de noter que netstat peut parfois renvoyer un pid mais pas le nom de l'exécutable correspondant!

eka808
la source
1

Le problème peut être causé si le processus mort a démarré un ou plusieurs processus enfants. Si

BOOL WINAPI CreateProcess(
_In_opt_    LPCTSTR               lpApplicationName,
_Inout_opt_ LPTSTR                lpCommandLine,
_In_opt_    LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_    LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_        BOOL                  bInheritHandles,
_In_        DWORD                 dwCreationFlags,
_In_opt_    LPVOID                lpEnvironment,
_In_opt_    LPCTSTR               lpCurrentDirectory,
_In_        LPSTARTUPINFO         lpStartupInfo,
_Out_       LPPROCESS_INFORMATION lpProcessInformation
);

a été utilisé pour démarrer un processus enfant, cela dépend de la valeur des handles hérités, donc avec

bInheritHandles = false 

Windows ne bloquera pas le port si le processus parent est arrêté et que le processus client est toujours en cours d'exécution.

V15I0N
la source
1

Nous avons rencontré un problème similaire lorsque la cause première était la création d’un processus enfant héritant des ports, le processus parent était bloqué, alors que le processus enfant détenait toujours le port. La solution consistait à identifier le processus enfant en cours d'exécution et à l'arrêter. Dans l'exemple ci-dessous, le PID de processus non existant était 7336

> wmic process get processid,parentprocessid | findstr/i 7336
7336             23828

Pour arrêter ce processus:

> taskkill /f /pid 23828

Et cela a résolu le problème.

Michael
la source
0

Je ne suppose pas que vous avez un pare-feu installé (ou essayé de tweeks réseau Windows)?

Certains pare-feu présentent ce type de comportement et peuvent maintenir les ports ouverts.

Si vous en avez un, essayez de le désactiver, puis lancez votre programme et fermez-le pour voir ce qui se passe.

William Hilsum
la source
Pas vraiment une option malheureusement, car je n’ai pas le contrôle du pare-feu sur mon ordinateur.
Srekel
@Srekel - de quel pare-feu s'agit-il? Comme vous avez des problèmes, je pense personnellement que c’est cela qui les cause.
William Hilsum
0

Étant donné que votre processus est répertorié en tant que système, vous pouvez probablement le supprimer à l'invite de commande "Système". Le compte système a plus de privilèges qu'un administrateur ordinaire.

Vous pouvez obtenir un cmd.exe "System" en planifiant une tâche pour cmd.exe (le planificateur s'exécute en tant que système):

at 15:23 /interactive "cmd.exe" 

Changer ce moment pour quelque chose dans un proche avenir. Assurez-vous également que vous êtes sur la console de l'ordinateur (si vous êtes sur une session de serveur Terminal Server normale, vous ne verrez pas le nouveau cmd.exe. Connectez-vous mstscà la console). Je suppose qu'il existe d'autres moyens de le faire, mais cela a fonctionné pour moi dans le passé.

David Suarez
la source
0

J'ai eu le même problème. Le processus était en cours de débogage alors qu'il se bloquait et il y avait encore un processus vsjitdebugger.exe en état suspendu qui faisait apparemment référence au processus en cours de débogage. Tuer ce processus vsjitdebugger.exe a résolu le problème.

gpvos
la source
0

Une utilisation hybride de TCPView et de Process Explorer a fonctionné pour moi;) J'ai d'abord cherché l'identifiant du processus qui utilisait le port dans TCPView. Isolé le processus dans Process Explorer et tué le processus à l'aide de Process Explorer.

Sathiya Narayanan
la source