Jak zabić proces, który jest martwy, ale słucha?

48

Tworzę aplikację, która nasłuchuje na porcie 3000. Najwyraźniej istnieje instancja tego, która nasłuchuje na porcie, ponieważ za każdym razem, gdy go uruchamiam, nie może utworzyć detektora (C #, TcpListener, ale to nie ma znaczenia), ponieważ port jest już wzięty.

Teraz aplikacja nie istnieje w Menedżerze zadań, więc próbowałem znaleźć jej PID i zabić go, co doprowadziło do tego ciekawego wyniku:

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.

Nie widziałem tego wcześniej i uznałem, że było wystarczająco interesujące, aby sprawdzić, czy ktoś ma rozwiązanie.

AKTUALIZACJA: Uruchomiłem Process Explorer, szukałem 3000 i znalazłem to:

<Non-existent Process>(3000): 5552

Kliknąłem go prawym przyciskiem myszy i wybrałem „Zamknij uchwyt”. Nie ma go już w Eksploratorze procesów, ale nadal pojawia się w netstat i nadal powstrzymuje aplikację przed uruchomieniem detektora.

AKTUALIZACJA 2: Znaleziono TCPView dla Windows, które pokazują proces jako "<non-existent>". Podobnie jak w przypadku CurrPorts, nic się nie dzieje, gdy próbuję zamknąć połączenie w tym narzędziu.

Srekel
źródło
trochę wyleczyć chorobę zabijając pacjenta, ale czy przestanie to, jeśli uruchomisz ponownie komputer?
Xantec,
2
W rzeczywistości wystarczyło wylogowanie i ponowne zalogowanie, ale udało mi się go odtworzyć, więc nadal chciałbym znaleźć lepsze rozwiązanie ...
Srekel,
Sprawdź, czy którykolwiek z programów wymienionych tutaj pomaga
Sathyajith Bhat
1
W bieżącej wersji TCPView 3.05 „Zamknij połączenie” z menu kontekstowego procesu <nie-exsitent> z powodzeniem zamknął połączenie w moim przypadku i zwolnił port.
Ventzy Kunev
1
Zobacz także serverfault.com/questions/181015/…
rogerdpack

Odpowiedzi:

13

Aby uniknąć niekończących się oczekiwań na gnieździe, twój program powinien używać funkcji setsockopt z parametrami SO_REUSEADDR i 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
źródło
1
Czy pomogło to komukolwiek z tym konkretnym problemem (nasłuchiwanie przez martwy proces)?
rustyx 17.07.17
12

Mieliśmy ten sam problem i użyliśmy Eksploratora procesów z Microsoft Sysinternals, aby wyszukać identyfikator procesu, który już nie istniał.

Okazuje się, że do procesu odwoływało się kilka procesów DrWatson. Zabicie tych procesów uwolniło port. DrWatson służy do wysyłania zrzutów pamięci do firmy Microsoft, co zajęło kilka godzin, ponieważ proces, który się zawiesił, obejmował kilkadziesiąt GB pamięci w tym czasie.

David
źródło
7

Myślę, że powinniśmy dać CurrPorts spróbować

CurrPorts to oprogramowanie do monitorowania sieci, które wyświetla listę wszystkich aktualnie otwartych portów TCP / IP i UDP na komputerze lokalnym. Dla każdego portu na liście wyświetlane są również informacje o procesie, który otworzył port, w tym nazwa procesu, pełna ścieżka procesu, informacje o wersji procesu (nazwa produktu, opis pliku itp.), Czas, w którym proces został utworzony, a użytkownik, który go utworzył.

Ponadto CurrPorts pozwala zamykać niechciane połączenia TCP, zabijać proces, który otworzył porty, i zapisywać informacje o portach TCP / UDP w pliku HTML, pliku XML lub pliku tekstowym rozdzielanym tabulatorami.

CurrPorts automatycznie zaznacza również podejrzane porty TCP / UDP w kolorze różowym, będące własnością niezidentyfikowanych aplikacji (aplikacje bez informacji o wersji i ikon)

alternatywny tekst

Sathyajith Bhat
źródło
4
Pojawia się na liście pod nazwą procesu „System”. Próbowałem kliknąć prawym przyciskiem myszy element, aby wymusić zamknięcie portu, ale nic się nie dzieje.
Srekel
7

Prawdopodobnym problemem jest to, że proces rozpoczął inny proces (potomny), który odziedziczył uchwyt gniazda i nadal działa.

Istnieją różne sposoby, aby temu zapobiec, na przykład: ProcessStartInfo UseShellExecute = true;

Nick Westgate
źródło
1
Dzięki, to było dobre. Dzwoniłem subprocess.call(..., cwd=..., shell=True)jako program uruchamiający aplikacje na serwerze sieci Python i okazało się, że musiałem zabić wszystkie te procesy potomne, aby zwolnić gniazdo. Dziwne jest to, że używam shell = True. Przez wieki mnie to denerwowało.
Daniel F
Nie sądzę, że użycie powłoki powoduje takie zachowanie. Jeśli chcesz, aby zakończyć wszystkie procesy potomne, gdy umiera rodzic, myślę, że jest poprawny sposób jest stworzenie obiektu zadania z flagą JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE , dodać każdy proces potomny z AssignProcessToJobObject , i pozwalają na dojście do blisko naturalnie Gdy wyjścia procesu macierzystego.
qris
1

Czy widzisz ten proces w Process Explorer ? Jeśli tak, możesz go zabić stamtąd, ale dopiero po zbadaniu, co to właściwie jest (możesz zobaczyć wszystkie pliki dll załadowane do procesu)

Jakub Konecki
źródło
1

Spróbuj rzucić flagę „-b” na komendzie netstat. Poda ci nazwę pliku wykonywalnego, który używa portu. Następnie znajdź ten proc w menedżerze zadań i zabij go tam. Jeśli to nie zadziała, opublikuj plik wykonywalny, który utrzymuje port otwarty.

Ge3ng
źródło
Obecnie nie mogę go odtworzyć, ale jestem prawie pewien, że skoro każda inna próba (i narzędzie) próby znalezienia nazwy procesu nie powiodła się, netstat też nie byłby w stanie tego zrobić.
Srekel,
1

Muszę tu wspomnieć o pojęciu „ linger” .

Szczegóły można znaleźć na stronie http://msdn.microsoft.com/en-us/library/ms739165.aspx

W skrócie: Istnieje opcja, która mówi systemowi gniazd, aby pozostawił gniazdo otwarte nawet po jego zamknięciu, jeśli obecne są niewysłane dane.

W aplikacji C # możesz określić dowolne powiązane opcje za pośrednictwem Socket.SetSocketOption: http://msdn.microsoft.com/en-us/library/1011kecd.aspx

Ponieważ wszystkie wspomniane rzeczy dotyczą wysyłania i klientów, ale mieliśmy podobne problemy w pracy, niektóre dalsze poszukiwania ujawniły, że można określić opcję linger dla słuchaczy, jak pokazano w przykładzie tutaj: http://msdn.microsoft.com /library/system.net.sockets.tcplistener.server.aspx

Niektórzy koledzy mówili o portach utrzymywanych przez system operacyjny po zakończeniu / zamknięciu aplikacji przez około dwie minuty. Biorąc to pod uwagę, ciekawie byłoby dowiedzieć się, czy port jest nadal utrzymywany po pewnym czasie.

Andreas
źródło
Porty były otwarte znacznie dłużej (nie pamiętam, jak długo, ale może do godziny, zanim się poddałem i zrestartowałem).
Srekel,
Nie jestem pewien, czy opcja linger jest odpowiednia w tym konkretnym przypadku, ponieważ wydaje się, że określa ona tylko, co powinno się stać po wywołaniu CloseSocket. Ponieważ zabijam aplikację, wątpię, aby ta funkcja została wywołana (?).
Srekel,
1

Też napotykam ten problem. W końcu znalazłem swój powód. Jest to spowodowane przez proces główny wywołany przez proces potomny przez popen w c / c ++. Ale główny proces ulega awarii / wyłączeniu przed wywołaniem pclose. Następnie port traktuje główny proces nadal na żywo i nadal go słucha.

lorry.lee
źródło
1
Uznałem tę odpowiedź za przydatną w ServerFault: serverfault.com/a/273727/8856
Harriv
1

Miałem ten sam problem z xdebug, pozostawił otwarty port 9000.

Udało mi się zamknąć za pomocą cmd przy użyciu „taskkill / pid xxxx”.

Identyfikator pid procesu korzystającego z portu można pobrać za pomocą polecenia „netstat -o”.

Moją konfiguracją było wygranie 7 domowych premii.

Christoforos
źródło
1

Miałem ten sam problem i naprawiłem go przez:

  • znalezienie PID za pomocą netstat -o
  • Zabij to za pomocą procesu xp

Ciekawe, że netstat może czasami zwrócić pid, ale nie odpowiednią nazwę pliku wykonywalnego!

eka808
źródło
1

Problem może zostać spowodowany, jeśli martwy proces rozpoczął jeden lub więcej procesów potomnych. Jeśli

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

został użyty do uruchomienia procesu potomnego, zależy to od wartości uchwytów dziedziczenia, więc z

bInheritHandles = false 

System Windows nie zablokuje portu, jeśli proces nadrzędny zostanie zatrzymany, a proces klienta będzie nadal działał.

V15I0N
źródło
1

widziałem podobny problem, gdy główną przyczyną był proces potomny utworzony przez dziedziczenie portów, proces nadrzędny ulegał awarii, podczas gdy proces potomny nadal utrzymywał port. Rozwiązaniem było zidentyfikowanie wciąż działającego procesu potomnego i zatrzymanie go. W podanym tutaj przykładzie nieistniejący PID procesu wynosił 7336

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

Aby zatrzymać ten proces:

> taskkill /f /pid 23828

I to rozwiązało problem.

Michael
źródło
0

Nie sądzę, że masz zainstalowaną zaporę ogniową (lub wypróbowałeś jakieś tweeksy sieciowe w systemie Windows)?

Niektóre zapory ogniowe wykazują takie zachowanie i mogą utrzymywać otwarte porty.

Jeśli tak, spróbuj je wyłączyć, a następnie uruchomić program, zamknąć go i zobaczyć, co się stanie.

William Hilsum
źródło
Niestety nie jest to opcja, ponieważ nie mam kontroli nad zaporą na moim komputerze.
Srekel,
@Srekel - co to jest firewall? Ponieważ masz problemy, osobiście uważam, że to one powodują problemy.
William Hilsum,
0

Ponieważ proces jest wymieniony jako System, najprawdopodobniej możesz go zabić w wierszu polecenia „System”. Konto systemowe ma więcej uprawnień niż zwykły administrator.

Możesz uzyskać „System” cmd.exe, planując zadanie dla cmd.exe (harmonogram działa jako System):

at 15:23 /interactive "cmd.exe" 

Zmień ten czas na coś w najbliższej przyszłości. Upewnij się również, że korzystasz z konsoli komputera (jeśli korzystasz z regularnej sesji serwera terminali, nie zobaczysz nowego cmd.exe. mstscZaloguj się do konsoli). Myślę, że istnieją inne sposoby, aby to zrobić, ale w przeszłości działało to dla mnie.

David Suarez
źródło
0

Miałem ten sam problem. Proces ten był debugowany podczas awarii, a proces vsjitdebugger.exe nadal pozostawał zawieszony, co najwyraźniej odnosiło się do debugowanego procesu. Zabicie tego procesu vsjitdebugger.exe rozwiązało problem.

GPVOS
źródło
0

Hybrydowe użycie TCPView i Process Explorer działało dla mnie;) Najpierw sprawdziłem identyfikator procesu, który używał portu w TCPView. Wyodrębniono proces w Eksploratorze procesów i zabito proces przy użyciu Eksploratora procesów.

Sathiya Narayanan
źródło