Na Linuksie uruchamiam określony program, który czasami ulega awarii. Jeśli otworzysz go szybko potem, będzie nasłuchiwał na gnieździe 49201 zamiast 49200, jak to robił za pierwszym razem. Netstat ujawnia, że 49200 jest w stanie TIME_WAIT.
Czy istnieje program, który można uruchomić, aby natychmiast zmusić to gniazdo do wyjścia ze stanu TIME_WAIT?
TIME_WAIT
na serwerze” , po prostu pomiń pierwsze trzy odpowiedzi, które unikają pytania, zamiast na nie odpowiadać.Odpowiedzi:
Pozwól mi rozwinąć. Protokół kontroli transmisji (TCP) został zaprojektowany jako dwukierunkowy, uporządkowany i niezawodny protokół transmisji danych między dwoma punktami końcowymi (programami). W tym kontekście termin niezawodny oznacza, że prześle pakiety ponownie, jeśli zgubi się w środku. TCP gwarantuje niezawodność, wysyłając z powrotem pakiety potwierdzenia (ACK) dla jednego lub szeregu pakietów otrzymanych od partnera.
To samo dotyczy sygnałów sterujących, takich jak żądanie / odpowiedź o zakończenie. RFC 793 definiuje stan CZAS OCZEKIWANIA w następujący sposób:
Zobacz następujący diagram stanu TCP:
TCP jest dwukierunkowym protokołem komunikacyjnym, więc po ustanowieniu połączenia nie ma różnicy między klientem a serwerem. Ponadto każdy z nich może wywoływać rezygnacje, a obydwaj uczestnicy muszą zgodzić się na zamknięcie, aby całkowicie zamknąć ustanowione połączenie TCP.
Zadzwońmy do pierwszego, który wywołuje wyjścia jako aktywny bliżej, a drugi do pasywnego bliżej. Kiedy aktywny bliżej wysyła FIN, stan przechodzi do FIN-WAIT-1. Następnie otrzymuje potwierdzenie dla wysłanego FIN, a stan przechodzi do FIN-WAIT-2. Gdy otrzyma FIN również z pasywnego bliższego, aktywny bliższy wysyła potwierdzenie do FIN, a stan przechodzi do CZASU OCZEKIWANIA. W przypadku, gdy pasywne zbliżenie nie otrzymało potwierdzenia do drugiego FIN, retransmituje pakiet FIN.
RFC 793 ustawia TIME-OUT na dwukrotność maksymalnego czasu życia segmentu lub 2MSL. Od czasu MSL maksymalny czas, w którym pakiet może wędrować po Internecie, jest ustawiony na 2 minuty, 2MSL to 4 minuty. Ponieważ nie ma ACK dla ACK, aktywne zamknięcie nie może zrobić nic innego, jak tylko czekać 4 minuty, jeśli poprawnie przestrzega protokołu TCP / IP, na wypadek, gdyby pasywny nadawca nie otrzymał ACK do jego FIN (teoretycznie) .
W rzeczywistości brakujące pakiety są prawdopodobnie rzadkie i bardzo rzadkie, jeśli wszystko dzieje się w sieci LAN lub na jednym komputerze.
Aby odpowiedzieć dosłownie na pytanie, jak przymusowo zamknąć gniazdo w TIME_WAIT ?, nadal będę trzymać się mojej oryginalnej odpowiedzi:
Praktycznie rzecz biorąc, zaprogramowałbym go tak, aby ignorował stan CZAS OCZEKIWANIA za pomocą opcji SO_REUSEADDR, jak wspomniano w WMR. Co dokładnie robi SO_REUSEADDR?
źródło
/etc/init.d/networking
jest specyficzna dla platformy (Debian?), Więc dokładna linia poleceń będzie inna (czasem raczej radykalna) dla innych systemów. Zgadzam się z innymi komentatorami, że wydaje się to poważną przesadą i oczywiście zakłócającą wszelkie niepowiązane usługi sieciowe.Nie wiem, czy masz kod źródłowy tego konkretnego programu, który uruchamiasz, ale jeśli tak, możesz po prostu ustawić SO_REUSEADDR, dzięki
setsockopt(2)
któremu możesz powiązać ten sam adres lokalny, nawet jeśli gniazdo jest w stanie TIME_WAIT (chyba że gniazdo aktywnie nasłuchuje, patrzsocket(7)
).Aby uzyskać więcej informacji na temat stanu TIME_WAIT, zobacz często zadawane pytania dotyczące gniazda Unix .
źródło
SO_REUSEADDR
nie „zamyka” gniazda. Pozwala jedynie ponownie wykorzystać te, które są już otwarte. Więc pytanie brzmi: „Jak przymusowo zamknąć gniazdoTIME_WAIT
?”SO_REUSEADDR
pozwolibind()
kontynuować; ale jeśli chcesz słuchać tego gniazda,listen()
zwróciEADDRINUSE
to samo. Innymi słowy, ta odpowiedź może pomóc oprogramowaniu klienckiemu używającym efemerycznych portów, ale nie rozwiązuje problemu z oprogramowaniem serwera.O ile wiem, nie ma sposobu, aby przymusowo zamknąć gniazdo poza napisaniem lepszego programu obsługi sygnałów w twoim programie, ale istnieje plik / proc, który kontroluje, jak długo trwa przekroczenie limitu czasu. Plik jest
i możesz ustawić limit czasu na 1 sekundę, wykonując następujące czynności:
Jednak ta strona zawiera ostrzeżenie o możliwych problemów z niezawodnością podczas ustawiania tej zmiennej.
Istnieje również powiązany plik
który kontroluje, czy gniazda TIME_WAIT mogą być ponownie użyte (prawdopodobnie bez przekroczenia limitu czasu).
Nawiasem mówiąc, dokumentacja jądra ostrzega, aby nie zmieniać żadnej z tych wartości bez „porad / wniosków ekspertów technicznych”. Którego nie jestem.
Program musi zostać napisany, aby podjąć próbę powiązania z portem 49200, a następnie zwiększyć o 1, jeśli port jest już w użyciu. Dlatego jeśli masz kontrolę nad kodem źródłowym, możesz zmienić to zachowanie, aby poczekać kilka sekund i spróbować ponownie na tym samym porcie, zamiast zwiększania.
źródło
1
działa dla przyszłych połączeń, ale co z tymi obecnymi, które są już otwarte?W rzeczywistości istnieje sposób na zabicie połączenia - killcx . Twierdzą, że działa w dowolnym stanie połączenia (którego nie zweryfikowałem). Musisz jednak znać interfejs, w którym odbywa się komunikacja, domyślnie przyjmuje się, że eth0.
AKTUALIZACJA: innym rozwiązaniem jest kuter, który jest dostępny w repozytoriach niektórych dystrybucji Linuksa.
źródło
Inną opcją jest użycie opcji SO_LINGER z limitem czasu 0. W ten sposób, kiedy zamykasz gniazdo, jest przymusowo zamykane, wysyłając RST zamiast przechodzić w zachowanie FIN / ACK. Pozwoli to uniknąć stanu TIME_WAIT i może być bardziej odpowiednie dla niektórych zastosowań.
źródło
Alternatywnym rozwiązaniem byłoby posiadanie pewnego niezawodnego oprogramowania proxy lub przekierowania portów, które nasłuchuje na porcie 49200, a następnie przekazywanie połączenia do jednego z kilku wystąpień mniej niezawodnego programu przy użyciu różnych portów ... HAPROXY przychodzi na myśl.
Nawiasem mówiąc, port, na którym się łączysz, jest dość wysoki. Możesz spróbować użyć nieużywanego tuż powyżej zakresu 0-1024. Twój system rzadziej używa niższego numeru portu jako portu efemerycznego.
źródło
TIME_WAIT jest najczęstszym problemem w architekturze serwerów klienckich programujących gniazda. Poczekaj kilka sekund, okresowe próby są najlepszym rozwiązaniem. Do aplikacji w czasie rzeczywistym potrzebują serwera, który musi natychmiast wstać. Istnieje dla nich opcja SO_REUSEADDR.
źródło