Jak usunąć połączenie gniazda CLOSE_WAIT

91

Napisałem mały program, który współdziała z serwerem na określonym porcie. Program działa dobrze, ale:

Raz program zakończył się nieoczekiwanie i od tego czasu połączenie przez gniazdo jest pokazane w CLOSE_WAITstanie. Jeśli próbuję uruchomić program, zawiesza się i muszę wymusić jego zamknięcie, co gromadzi jeszcze więcej CLOSE_WAIT połączeń gniazd.

Czy istnieje sposób na przepłukanie tych połączeń?

Dilletante
źródło
4
Nie możesz (i nie powinieneś). CLOSE_WAIT to stan zdefiniowany przez TCP dla połączeń, które są zamykane i czekają na potwierdzenie przez odpowiednika.
vonbrand,
1
Zobacz także unix.stackexchange.com/questions/10106/ ... ... na które nie głosuję jako duplikat, ponieważ w końcu pytanie to zamknęłoby się jako nie na temat.
derobert
3
@vonbrand Nie, nie jest, jest dokładnie odwrotnie. Jest to stan połączenia, które zostało już zamknięte przez peera i czeka, aż aplikacja lokalna zamknie swoje zakończenie.
Markiz Lorne
Jeśli używasz Commons HttpClient, to nuxeo.com/blog/… zawiera wiele przydatnych informacji. Z RFC 2616, sekcja 14: Aplikacje HTTP / 1.1, które nie obsługują połączeń trwałych, MUSZĄ zawierać opcję połączenia „zamknij” w każdej wiadomości.
Mayank Ahuja

Odpowiedzi:

79

CLOSE_WAIToznacza, że ​​twój program nadal działa i nie zamknął gniazda (a jądro czeka, aż to zrobi). Dodaj -pdo, netstataby uzyskać pid, a następnie zabij go mocniej (w SIGKILLrazie potrzeby za pomocą). To powinno pozbyć się twoich CLOSE_WAITgniazd. Możesz również użyć, psaby znaleźć pid.

SO_REUSEADDRdotyczy serwerów i TIME_WAITgniazd, więc nie ma tutaj zastosowania.

derobert
źródło
2
cóż ... zabijanie procesu może nie być najlepsze, jeśli ten program otwiera wiele połączeń, tylko kilka z tych pozostających w "CLOSE_WAIT": w takim przypadku zabicie procesu może być całkowicie niemożliwe lub niewłaściwe (program nadal działa i świadczy usługi z tymi innymi połączeniami). Samo zamknięcie oczekującego połączenia byłoby znacznie bardziej odpowiednie. ale w rzeczywistości to zwykle sam program nie zamyka lokalnie connectino (CLOSE_WAIT oznacza, że ​​otrzymał 'FIN' z drugiego końca i program musi tylko lokalnie zamknąć połączenie). Zgłoszenie błędu może być odpowiednie
Olivier Dulac
40

Jak opisał Crist Clark .

CLOSE_WAIT oznacza, że ​​lokalny koniec połączenia otrzymał FIN z drugiego końca, ale system operacyjny czeka, aż program na lokalnym końcu faktycznie zamknie połączenie.

Problem polega na tym, że program działający na komputerze lokalnym nie zamyka gniazda. Nie jest to kwestia strojenia TCP. Połączenie może (i całkiem poprawnie) pozostać w CLOSE_WAIT na zawsze, podczas gdy program utrzymuje je otwarte.

Gdy program lokalny zamknie gniazdo, system operacyjny może wysłać FIN do zdalnego końca, który przechodzi do LAST_ACK, podczas gdy czekasz na potwierdzenie FIN. Po odebraniu połączenie jest zakończone i znika z tabeli połączeń (jeśli twój koniec jest w CLOSE_WAIT, nie znajdziesz się w stanie TIME_WAIT).

user2618402
źródło
4
jak zamknąć gniazdo ??
Divyang Shah
1
Zamykasz uchwyt, który masz, do gniazda, które otworzyłeś. Użyj close()lub closesocket(), w zależności od używanej platformy.
Remy Lebeau
8

Mam również ten sam problem z najnowszym serwerem Tomcat (7.0.40). Nie reaguje raz na kilka dni.

Aby zobaczyć otwarte połączenia, możesz użyć:

sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT

Jak wspomniano w tym poście , możesz użyć, /proc/sys/net/ipv4/tcp_keepalive_timeaby wyświetlić wartości. Wydaje się, że wartość jest wyrażona w sekundach i domyślnie wynosi 7200 (tj. 2 godziny).

Aby je zmienić, musisz edytować /etc/sysctl.conf.

Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`
Amil Waduwawara
źródło
4
odpowiedź jest zagmatwana. powiedziałeś, że stany braku reakcji minęły od kilku dni ... ale potem też próbujesz ustawić czas podtrzymania aktywności na zaledwie 120 sekund. nawet przy domyślnej wartości (7200 sek.) nie powinno to trwać kilka dni, prawda?
fanchyna
8

Nawet jeśli zbyt wiele połączeń CLOSE_WAIT oznacza, że ​​coś jest nie tak z twoim kodem w pierwszym i jest to akceptowane, nie jest dobrą praktyką.

Możesz sprawdzić: https://github.com/rghose/kill-close-wait-connections

To, co robi ten skrypt, to wysłanie ACK, na które czekało połączenie.

To właśnie zadziałało dla mnie.

miraż
źródło
wysyłasz act do gniazda close-wait. z nie działa .. jeśli działa to dlaczego?
Chinaxing
Domyślam się, że system operacyjny wysłał już FIN do zdalnego hosta. Zdalny host prawdopodobnie nie może odpowiedzieć potwierdzeniem ACK, którego oczekuje gniazdo.
miraż
tak, zgadza się (z kodu jądra). ale wątpię również w SEQ wysyłanego pakietu, które wynosi „10”, czy jądro go nie sprawdza?
Chinaxing
Prawdopodobnie nie. Myślę, że próbowałem z wieloma przypadkowymi liczbami i wydawało się, że działają.
miraż
3

Należy wspomnieć, że Socketinstancja po stronie klienta i serwera musi być jawnie wywoływana close(). Jeśli close()wywoła to również tylko jeden koniec , gniazdo pozostanie w stanie CLOSE_WAIT.

Binita Bharati
źródło
3

Możesz wymusić zamknięcie gniazd za pomocą sspolecenia; sskomenda jest narzędziem służącym do zrzutu statystyki gniazd i wyświetla informacje w podobny sposób (choć prostsze i szybsze) do netstat.

Aby zabić dowolne gniazdo w stanie CLOSE_WAIT, uruchom to (jako root)

$ ss --tcp state CLOSE-WAIT --kill
Mustapha Hadid
źródło
1

Warto również zauważyć, że jeśli program uruchomi nowy proces, ten proces może odziedziczyć wszystkie otwarte uchwyty. Nawet po zamknięciu własnego programu te odziedziczone uchwyty mogą nadal istnieć dzięki procesowi osieroconego dziecka. I niekoniecznie pojawiają się tak samo w netstacie. Ale mimo wszystko gniazdo będzie się kręcić w CLOSE_WAIT, gdy ten proces potomny będzie żył.

Miałem przypadek, w którym prowadziłem ADB. Sam ADB uruchamia proces serwera, jeśli nie jest jeszcze uruchomiony. To początkowo odziedziczyło wszystkie moje uchwyty, ale nie pojawiło się jako posiadanie żadnego z nich, gdy badałem (to samo dotyczyło zarówno systemu MacOS, jak i Windows - nie jestem pewien co do Linuksa).

Ian
źródło