Как убить процесс, который мертв, но слушает?

48

Я разрабатываю приложение, которое прослушивает порт 3000. Очевидно, есть экземпляр, который все еще слушает порт, потому что всякий раз, когда я запускаю его, он не может создать прослушиватель (C #, TcpListener, но это не имеет значения), потому что порт уже приняты.

Теперь приложение не существует в диспетчере задач, поэтому я попытался найти его PID и убить его, что привело к интересному результату:

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.

Я не видел такого поведения раньше и подумал, что это достаточно интересно, чтобы увидеть, есть ли у кого-нибудь решение.

ОБНОВЛЕНИЕ: я запустил Process Explorer, выполнил поиск 3000 и нашел это:

<Non-existent Process>(3000): 5552

Я щелкнул правой кнопкой мыши по нему и выбрал «Закрыть ручку». Его больше нет в Process Explorer, но он все еще отображается в netstat и все еще не позволяет приложению запустить слушатель.

ОБНОВЛЕНИЕ 2: Найдено TCPView для Windows, которые показывают процесс как "<non-existent>". Как и в случае с CurrPorts, ничего не происходит, когда я пытаюсь закрыть соединение в этом инструменте.

Srekel
источник
немного вылечить болезнь, убив пациента, но остановится ли это, если вы перезагрузите компьютер?
Ксантек
2
На самом деле достаточно было выйти из системы и снова войти в нее, но теперь мне удалось воспроизвести ее, поэтому я все же хотел бы найти лучшее решение ...
Срекел
Проверьте, помогает ли какая-либо из перечисленных здесь программ
Сатьяджит Бхат
1
В текущей версии TCPView 3.05 «Закрыть соединение» из контекстного меню процесса <non-exsitent> успешно закрыло соединение в моем случае и освободило порт.
Венцы Кунев
1
Смотрите также serverfault.com/questions/181015/...
rogerdpack

Ответы:

13

Чтобы избежать бесконечного ожидания в сокете, ваша программа должна использовать функцию setsockopt с параметрами SO_REUSEADDR и 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
источник
1
Помогло ли это кому-нибудь с этой конкретной проблемой (прослушивание сокета мертвым процессом)?
rustyx
12

У нас была та же проблема, и мы использовали Process Explorer от Microsoft Sysinternals для поиска ID процесса, который больше не существовал.

Оказывается, на этот процесс ссылались несколько процессов DrWatson. Убив эти процессы освободил порт. DrWatson используется для отправки дампов памяти в Microsoft, и это занимало несколько часов, потому что сбойный процесс занимал несколько десятков ГБ памяти в то время.

Дэвид
источник
7

Я думаю, вы должны попробовать CurrPorts

CurrPorts - это программное обеспечение для мониторинга сети, которое отображает список всех открытых на данный момент портов TCP / IP и UDP на вашем локальном компьютере. Для каждого порта в списке также отображается информация о процессе, открывшем порт, включая имя процесса, полный путь процесса, информацию о версии процесса (название продукта, описание файла и т. Д.), Время, в течение которого процесс был создан, и пользователь, который создал его.

Кроме того, CurrPorts позволяет закрывать нежелательные TCP-соединения, завершать процесс, который открыл порты, и сохранять информацию о портах TCP / UDP в файл HTML, файл XML или текстовый файл с разделителями табуляции.

CurrPorts также автоматически помечает розовым цветом подозрительные порты TCP / UDP, принадлежащие неопознанным приложениям (приложения без информации о версии и значков)

альтернативный текст

Сатьяджит Бхат
источник
4
Он отображается в списке под именем процесса «Система». Я попытался щелкнуть правой кнопкой мыши по пункту, чтобы принудительно закрыть порт, но ничего не происходит.
Срекел
7

Вероятная проблема заключается в том, что ваш процесс запустил другой (дочерний) процесс, который унаследовал дескриптор сокета, и он все еще выполняется.

Существует несколько способов предотвратить это, например: ProcessStartInfo.UseShellExecute = true;

Ник Вестгейт
источник
1
Спасибо, это было хорошо. Я звонил subprocess.call(..., cwd=..., shell=True)как средство запуска приложений на веб-сервере python, и оказалось, что мне нужно было убить все эти дочерние процессы, чтобы освободить сокет. Странно то, что я использую shell = True. Это меня раздражало целую вечность.
Даниэль Ф
Я не думаю, что использование оболочки приводит к такому поведению. Если вы хотите завершить все дочерние процессы, когда умирает родительский процесс, я думаю, что правильным способом является создание объекта задания с флагом JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE , добавление каждого дочернего процесса с помощью AssignProcessToJobObject и естественное закрытие дескриптора при выходе из родительского процесса.
Крис
1

Можете ли вы увидеть процесс в Process Explorer ? Если да, то вы можете убить его оттуда, но только после того, как вы исследуете, что это на самом деле (вы можете увидеть все dll, загруженные в процесс)

Якуб Конецки
источник
1

Попробуйте добавить флаг '-b' в команду netstat. Он скажет вам имя исполняемого файла, который использует порт. Затем найдите этот процесс в диспетчере задач и убейте его там. Если это не сработает, то укажите, какой исполняемый файл удерживает порт открытым.

Ge3ng
источник
Я не могу воспроизвести его в данный момент, но я почти уверен, что, поскольку любая другая попытка (и инструмент) попытаться найти имя процесса не удалась, netstat также не смог бы это сделать.
Srekel
1

Нужно упомянуть термин задержаться здесь.

Подробности можно найти на http://msdn.microsoft.com/en-us/library/ms739165.aspx

Вкратце: есть опция, которая сообщает системе сокетов держать сокет открытым даже после его закрытия, если присутствуют неотправленные данные.

В вашем приложении C # вы можете указать любые связанные параметры через Socket.SetSocketOption: http://msdn.microsoft.com/en-us/library/1011kecd.aspx

Поскольку все упомянутое относится к отправке и клиентам, но у нас были похожие проблемы в работе, некоторые дальнейшие поиски показали, что можно указать опцию linger для слушателей, как показано в примере здесь: http://msdn.microsoft.com /library/system.net.sockets.tcplistener.server.aspx

Некоторые коллеги говорили о том, что порты удерживаются ОС после завершения / закрытия приложения в течение примерно двух минут. Учитывая это, было бы интересно узнать, удерживается ли порт по прошествии определенного времени.

Andreas
источник
Порты были открыты гораздо дольше (не помню, как долго, но, может быть, за час до того, как я сдался и перезагрузился).
Srekel
Я не уверен, относится ли опция linger к данному конкретному случаю, так как кажется, что она определяет только то, что должно произойти после вызова CloseSocket. Поскольку я убиваю приложение, я сомневаюсь, что функция вызывается (?).
Srekel
1

Я также сталкиваюсь с этой проблемой. Наконец я нашел причину. Это вызвано тем, что основной процесс вызывает дочерний процесс popen в c / c ++. Но основной процесс сбоя / выключения перед вызовом pclose. Тогда порт будет обрабатывать основной процесс еще живым и все равно слушать его.

lorry.lee
источник
1
Я нашел этот ответ на ServerFault полезным: serverfault.com/a/273727/8856
Harriv 18.12.12
1

У меня была такая же проблема с xdebug, он оставил порт 9000 открытым.

Мне удалось закрыть с помощью cmd с помощью «taskkill / pid xxxx».

PID процесса, использующего порт, можно получить с помощью «netstat -o».

Моя конфигурация была выиграть 7 премиум дома.

Christoforos
источник
1

У меня была та же проблема, и я исправил ее:

  • найти PID с netstat -o
  • Убить его с помощью процесса XP

Интересно отметить, что иногда netstat может возвращать pid, но не соответствующее имя исполняемого файла!

eka808
источник
1

Проблема может быть вызвана, если мертвый процесс запустил один или несколько дочерних процессов. Если

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
);

был использован для запуска дочернего процесса, это зависит от значения дескрипторов наследования, поэтому с

bInheritHandles = false 

Windows не будет блокировать порт, если родительский процесс остановлен, а клиентский процесс все еще выполняется.

V15I0N
источник
1

видел аналогичную проблему, когда основной причиной был какой-то дочерний процесс, созданный унаследовав порты, родительский процесс потерпел крах, в то время как дочерний процесс все еще удерживал порт. Было решено определить дочерний процесс, который все еще работает, и остановить его. В этом примере PID несуществующего процесса был 7336

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

Чтобы остановить этот процесс:

> taskkill /f /pid 23828

И это решило проблему.

Майкл
источник
0

Я не думаю, что у вас установлен брандмауэр (или вы попробовали какие-либо твики для работы в сети Windows)?

Некоторые брандмауэры демонстрируют такое поведение и могут держать порты открытыми.

Если он у вас есть, попробуйте отключить его, а затем запустить программу, закрыть ее и посмотреть, что произойдет.

Уильям Хилсум
источник
К сожалению, это не вариант, так как я не контролирую брандмауэр на моем компьютере.
Srekel
@Srekel - что это за брандмауэр? Поскольку у вас есть проблемы, я лично думаю, что это вызывает проблемы.
Уильям Хилсум
0

Поскольку ваш процесс указан как Системный, скорее всего вы можете убить его в командной строке «Система». Системная учетная запись имеет больше привилегий, чем обычный администратор.

Вы можете получить «System» cmd.exe, запланировав задачу для cmd.exe (планировщик работает как System):

at 15:23 /interactive "cmd.exe" 

Измените это время на что-то в ближайшем будущем. Также убедитесь, что вы находитесь на консоли компьютера (если вы находитесь на обычном сеансе сервера терминалов, вы не увидите новый cmd.exe. Выполните mstscвход в консоль). Я думаю, что есть другие способы сделать это, но это работало для меня в прошлом.

Дэвид Суарес
источник
0

У меня была такая же проблема. Процесс был отлажен во время сбоя, и процесс vsjitdebugger.exe все еще находился в приостановленном состоянии, что, по-видимому, относилось к отлаживаемому процессу. Уничтожение этого процесса vsjitdebugger.exe решило проблему.

gpvos
источник
0

Гибридное использование TCPView и Process Explorer работало для меня;) Сначала я посмотрел на идентификатор процесса, который использовал порт в TCPView. Изолировал процесс в Process Explorer и убил процесс с помощью Process Explorer.

Сатия Нараянан
источник