¿Cómo elimino un proceso que está muerto pero que escucha?

48

Estoy desarrollando una aplicación que escucha en el puerto 3000. Aparentemente hay una instancia de que todavía escucha el puerto porque cada vez que lo inicio, no puede crear un escucha (C #, TcpListener, pero eso es irrelevante) porque el puerto ya está tomado.

Ahora, la aplicación no existe en el Administrador de tareas, así que traté de encontrar su PID y matarlo, lo que condujo a este resultado interesante:

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.

No he visto este comportamiento antes y pensé que era lo suficientemente interesante como para ver si alguien tiene una solución.

ACTUALIZACIÓN: inicié Process Explorer e hice una búsqueda de 3000 y encontré esto:

<Non-existent Process>(3000): 5552

Hice clic derecho sobre él y elegí "Cerrar asa". Ya no está en Process Explorer, pero aún aparece en netstat y todavía detiene la aplicación para que no inicie el oyente.

ACTUALIZACIÓN 2: Se encontró TCPView para Windows que muestra el proceso como "<non-existent>". Al igual que con CurrPorts, no sucede nada cuando intento cerrar la conexión en esta herramienta.

Srekel
fuente
cura un poco la enfermedad matando al paciente, pero ¿se detiene si reinicia la computadora?
Xantec
2
De hecho, cerrar sesión y volver a iniciarla fue suficiente, pero ahora he logrado reproducirlo, así que todavía me gustaría encontrar una solución mejor ...
Srekel
Compruebe si alguno de los programas enumerados aquí ayuda
Sathyajith Bhat
1
Con la versión actual de TCPView 3.05 "Cerrar conexión" desde el menú contextual del proceso <no existente> cerró con éxito la conexión en mi caso y liberó el puerto.
Ventzy Kunev
1
Ver también serverfault.com/questions/181015/…
rogerdpack

Respuestas:

13

Para evitar esperas interminables en el socket, su programa debe usar la función setsockopt con los parámetros SO_REUSEADDR y 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
fuente
1
¿Esto ayudó a alguien con este problema en particular (escucha de socket por un proceso inactivo)?
rustyx
12

Tuvimos el mismo problema y utilizamos Process Explorer de Microsoft Sysinternals para buscar el ID de proceso que ya no existía.

Resulta que el proceso fue referenciado por varios procesos DrWatson. Matar esos procesos liberó el puerto. DrWatson se usa para enviar volcados de memoria a Microsoft y esto estaba tomando varias horas porque el proceso que se bloqueó contenía varias decenas de GB de memoria en ese momento.

David
fuente
7

Creo que deberías probar CurrPorts

CurrPorts es un software de monitoreo de red que muestra la lista de todos los puertos TCP / IP y UDP abiertos actualmente en su computadora local. Para cada puerto de la lista, también se muestra información sobre el proceso que abrió el puerto, incluido el nombre del proceso, la ruta completa del proceso, la información de la versión del proceso (nombre del producto, descripción del archivo, etc.), el tiempo que se creó el proceso y el usuario que lo creó.

Además, CurrPorts le permite cerrar conexiones TCP no deseadas, eliminar el proceso que abrió los puertos y guardar la información de los puertos TCP / UDP en un archivo HTML, un archivo XML o un archivo de texto delimitado por tabulaciones.

CurrPorts también marca automáticamente con puertos TCP / UDP sospechosos de color rosa propiedad de aplicaciones no identificadas (Aplicaciones sin información de versión e iconos)

texto alternativo

Sathyajith Bhat
fuente
44
Aparece en la lista bajo el nombre del proceso "Sistema". Intenté hacer clic derecho en el elemento para forzar el cierre del puerto, pero no sucede nada.
Srekel el
7

El problema probable es que su proceso ha iniciado otro proceso (secundario) que heredó el controlador de socket y aún se está ejecutando.

Hay varias formas de evitar esto, por ejemplo: ProcessStartInfo.UseShellExecute = true;

Nick Westgate
fuente
1
Gracias, esta fue buena. Estaba llamando subprocess.call(..., cwd=..., shell=True)como lanzador de aplicaciones en un servidor web de Python, y resultó que tenía que matar todos esos procesos secundarios para liberar el socket. Lo extraño es que estoy usando shell = True. Esto me molestó por años.
Daniel F
No creo que usar un shell provoque este comportamiento. Si desea finalizar todos los procesos secundarios cuando el principal fallece, creo que la forma correcta es crear un objeto de trabajo con el indicador JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE , agregar cada proceso secundario con AssignProcessToJobObject y permitir que el controlador se cierre de forma natural cuando el proceso principal se cierre.
qris
1

¿Puedes ver el proceso en Process Explorer ? En caso afirmativo, puede matarlo desde allí, pero solo después de investigar qué es realmente (puede ver todos los dlls cargados en el proceso)

Jakub Konecki
fuente
1

Intente lanzar una bandera '-b' en su comando netstat. Le indicará el nombre del ejecutable que está utilizando el puerto. Luego encuentra ese proceso en el administrador de tareas y mátalo allí. Si eso no funciona, publique cuál es el ejecutable que mantiene abierto el puerto.

Ge3ng
fuente
No puedo reproducirlo en este momento, pero estoy bastante seguro de que, dado que cualquier otro intento (y herramienta) para tratar de encontrar el nombre del proceso falló, netstat tampoco habría podido hacerlo.
Srekel
1

Necesito mencionar el término persistir aquí.

Los detalles se pueden encontrar en http://msdn.microsoft.com/en-us/library/ms739165.aspx

En resumen: hay una opción que le dice al sistema de socket que mantenga un socket abierto incluso después de que se haya cerrado si hay datos no enviados.

En su aplicación C #, puede especificar cualquier opción relacionada a través de Socket.SetSocketOption: http://msdn.microsoft.com/en-us/library/1011kecd.aspx

Dado que todo lo mencionado está relacionado con el envío y los clientes, pero tuvimos problemas similares en el trabajo, algunas búsquedas posteriores revelaron que uno podría especificar la opción de retraso para los oyentes como se muestra en el ejemplo aquí: http://msdn.microsoft.com /library/system.net.sockets.tcplistener.server.aspx

Algunos colegas hablaron sobre los puertos retenidos por el sistema operativo después de la finalización / cierre de la aplicación durante aproximadamente dos minutos. Dado eso, sería interesante saber si el puerto aún se mantiene después de un cierto período de tiempo.

Andreas
fuente
Los puertos se mantuvieron abiertos durante mucho más tiempo que eso (no recuerdo cuánto tiempo, pero tal vez hasta una hora antes de que me diera por vencido y reiniciara).
Srekel
No estoy seguro de si la opción persistente es relevante para este caso en particular, ya que parece que solo especifica lo que se supone que sucederá después de una llamada a CloseSocket. Como estoy matando la aplicación, dudo que esa función se llame (?).
Srekel
1

También me encuentro con este problema. Finalmente encontré mi razón. Es causada por el proceso principal invocado a un proceso secundario por popen en c / c ++. Pero el proceso principal se bloquea / apaga antes de invocar pclose. Luego, el puerto tratará el proceso principal aún en vivo y aún lo escuchará.

camión.lee
fuente
1
Encontré útil esta respuesta en ServerFault: serverfault.com/a/273727/8856
Harriv
1

Tuve el mismo problema con xdebug, dejó el puerto 9000 abierto.

Logré cerrar con cmd usando "taskkill / pid xxxx".

El pid del proceso que usa el puerto se puede recuperar con "netstat -o".

Mi configuración fue win 7 home premium.

Christoforos
fuente
1

Tuve el mismo problema y lo solucioné:

  • encontrar el PID con netstat -o
  • Mátalo con proceso xp

¡Es interesante notar que netstat a veces puede devolver un pid pero no el nombre ejecutable correspondiente!

eka808
fuente
1

El problema puede ser causado si el proceso inactivo ha iniciado uno o más procesos secundarios. 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
);

se utilizó para iniciar un proceso secundario, depende del valor de los identificadores de herencia, por lo que con

bInheritHandles = false 

Windows no bloqueará el puerto si el proceso principal se detiene y el proceso del cliente aún se está ejecutando.

V15I0N
fuente
1

Vimos un problema similar cuando la causa raíz era un proceso hijo creado heredando los puertos, el proceso padre se bloqueaba, mientras que el proceso hijo aún mantenía el puerto. La resolución fue identificar el proceso secundario que aún se está ejecutando y detenerlo. En el ejemplo aquí, el PID de proceso no existente era 7336

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

Para detener este proceso:

> taskkill /f /pid 23828

Y esto resolvió el problema.

Miguel
fuente
0

¿Supongo que no tienes un firewall instalado (o has probado algunos tweeks de red de Windows)?

Algunos cortafuegos exhiben este tipo de comportamiento y pueden mantener abiertos los puertos.

Si tiene uno, intente deshabilitarlo y luego inicie su programa y ciérrelo para ver qué sucede.

William Hilsum
fuente
Desafortunadamente, no es una opción, ya que no tengo control del firewall en mi computadora.
Srekel
@Srekel: ¿qué firewall es? Como tiene problemas, personalmente creo que es la causa de los problemas.
William Hilsum
0

Dado que su proceso aparece como Sistema, lo más probable es que pueda eliminarlo en el símbolo del sistema "Sistema". La cuenta del sistema tiene más privilegios que un administrador regular.

Puede obtener cmd.exe "Sistema" programando una tarea para cmd.exe (el programador se ejecuta como Sistema):

at 15:23 /interactive "cmd.exe" 

Cambie ese tiempo por algo en el futuro cercano. Asegúrese también de que está en la consola de la máquina (si está en una sesión normal de Terminal Server, no verá el nuevo cmd.exe. Inicie mstscsesión en la consola). Creo que hay otras formas de hacerlo, pero esto funcionó para mí en el pasado.

David Suárez
fuente
0

Yo tuve el mísmo problema. El proceso se estaba depurando mientras se bloqueaba, y todavía había un proceso vsjitdebugger.exe en un estado suspendido persistente, que aparentemente se refería al proceso que se estaba depurando. Matar ese proceso vsjitdebugger.exe resolvió el problema.

gpvos
fuente
0

Un uso híbrido de TCPView y Process Explorer funcionó para mí;) Primero busqué en la identificación del proceso que estaba usando el puerto en TCPView. Aisló el proceso en Process Explorer y eliminó el proceso usando Process Explorer.

Sathiya Narayanan
fuente