Wiem, że istnieje wiele pytań na ten temat i uważam, że przeczytałem tyle z nich, ile ma to znaczenie, zanim dojdę do tego punktu.
Pod pojęciem „po stronie serwera TIME_WAIT
” rozumiem stan pary gniazd po stronie serwera, której zainicjowano funkcję close () po stronie serwera.
Często widzę te stwierdzenia, które wydają mi się sprzeczne:
- Po stronie serwera
TIME_WAIT
jest nieszkodliwy - Powinieneś zaprojektować swoje aplikacje sieciowe tak, aby klienci inicjowali close (), dlatego też klient musi to zrobić
TIME_WAIT
Powodem, dla którego uważam to za sprzeczne, jest to, że TIME_WAIT
na kliencie może być problem - klient może zabraknąć dostępnych portów, więc w zasadzie powyższe zaleca przeniesienie ciężaru TIME_WAIT
na stronę klienta, gdzie może być problem, z po stronie serwera, gdzie nie stanowi to problemu.
Po stronie klienta TIME_WAIT
jest oczywiście problem tylko w ograniczonej liczbie przypadków użycia. Większość rozwiązań klient-serwer obejmowałaby jeden serwer i wielu klientów, klienci zwykle nie radzą sobie z wystarczająco dużą liczbą połączeń, aby stanowiło to problem, a nawet jeśli tak, istnieje szereg zaleceń dotyczących „zdrowego” ( w przeciwieństwie do SO_LINGER
limitu czasu 0 lub wtrącania się w sysctls tcp_tw) walcz po stronie klienta TIME_WAIT
, unikając zbyt szybkiego tworzenia zbyt wielu połączeń. Ale nie zawsze jest to wykonalne, na przykład w przypadku klas aplikacji takich jak:
- systemy monitorowania
- generatory obciążenia
- pełnomocnicy
Z drugiej strony nawet nie rozumiem, w jaki sposób po stronie serwera TIME_WAIT
jest w ogóle pomocna. Powodem TIME_WAIT
jest nawet to, że zapobiega wstrzykiwaniu starych TCP
fragmentów do strumieni, do których już nie należą. Po stronie klienta TIME_WAIT
osiąga się to po prostu przez uniemożliwienie utworzenia połączenia z tymi samymi ip:port
parami, które mogło mieć to nieaktualne połączenie (używane pary są zablokowane TIME_WAIT
). Ale po stronie serwera nie można temu zapobiec, ponieważ adres lokalny będzie miał port akceptujący i zawsze będzie taki sam, a serwer nie może (AFAIK, mam tylko dowód empiryczny) po prostu dlatego, że połączenie przychodzący peer utworzyłby tę samą parę adresów, która już istnieje w tabeli gniazd.
Napisałem program, który pokazuje, że TIME-WAIT po stronie serwera są ignorowane. Ponadto, ponieważ test został przeprowadzony na 127.0.0.1, jądro musi mieć specjalny bit, który mówi mu nawet, czy jest to po stronie serwera, czy po stronie klienta (ponieważ w przeciwnym razie krotka byłaby taka sama).
Źródło: http://pastebin.com/5PWjkjEf , przetestowane na Fedorze 22, domyślna konfiguracja sieci.
$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp TIME-WAIT 0 0 127.0.0.1:44400 127.0.0.1:44401
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address
Tak więc, po stronie serwera TIME_WAIT
, połączenia na dokładnie tej samej parze portów mogą zostać natychmiast i pomyślnie ustanowione ponownie, a po stronie klienta TIME-WAIT
, podczas drugiej iteracji connect()
nie powiodło się
Podsumowując, pytanie jest dwojakie:
- Czy po stronie serwera
TIME_WAIT
tak naprawdę nic nie robi i tak zostało, ponieważRFC
wymaga tego? - Czy powodem jest to, że klient powinien zainicjować close (), ponieważ serwer
TIME_WAIT
jest bezużyteczny?
TIME_WAIT
.Odpowiedzi:
W terminach TCP po stronie serwera oznacza tutaj host, który ma gniazdo w stanie LISTEN.
RFC1122 pozwala gniazdu w stanie TIME-WAIT zaakceptować nowe połączenie z pewnymi warunkami
Aby uzyskać szczegółowe informacje na temat warunków, zobacz RFC1122 . Spodziewałbym się, że na gnieździe musi również znajdować się pasywne OTWIERANIE pasywne (gniazdo w stanie LISTEN).
Aktywne OPEN (wywołanie połączenia po stronie klienta) nie ma takiego wyjątku i musi dawać błąd, gdy gniazdo jest w trybie CZAS OCZEKIWANIA, zgodnie z RFC793 .
Domyślam się, że zalecenie dla klienta (w kategoriach TCP host wykonujący aktywne OTWÓRZ tj. Połącz) zainicjowane zamknięcie jest bardzo podobne do twojego, ponieważ w powszechnym przypadku rozkłada gniazda TIME-WAIT na większej liczbie hostów, na których jest mnóstwo zasobów dla gniazda. W typowym przypadku klienci nie wysyłają SYN, który ponownie używałby gniazd TIME-WAIT na serwerze. Zgadzam się, że zastosowanie takiej rekomendacji nadal zależy od przypadku użycia.
źródło
Jest to prawdopodobnie najbardziej wyraźny przykład tego, co faktycznie robi CZAS OCZEKIWANIA, a co ważniejsze, dlaczego jest taki ważny. Wyjaśnia również, dlaczego należy unikać niektórych „eksperckich” porad dotyczących maszyn z systemem Linux, aby „skrócić” CZAS OCZEKIWANIA.
źródło
Sesja tcp jest identyfikowana przez krotkę (sourceIP, sourcePort, destIP, destPort). Dlatego TIME_WAIT działa na każdym połączeniu TCP.
Jeśli chodzi o stronę zamykającą, w niektórych scenariuszach zamknięcie po stronie klienta może zmniejszyć liczbę gniazd TIME_WAIT na serwerze, a tym samym nieznacznie zmniejszyć pamięć. W przypadkach, gdy przestrzeń gniazd może zostać wyczerpana (z powodu efemerycznego wyczerpania portu) (np. Chciwi klienci z wieloma połączeniami z tym samym serwerem), problem ten należy rozwiązać z dowolnej strony.
źródło
TIME_WAIT
(zaktualizowałem pytanie o te informacje). @ Odniesienie Khushila nie obejmujeTIME_WAIT
wystarczająco szczegółowo przypadków po stronie serwera .Nigdy nie możesz mieć pewności co do niewiarygodnego protokołu, że otrzymałeś ostatnią wiadomość z urządzenia równorzędnego, dlatego niebezpieczne jest założenie, że twój rówieśnik odłożył słuchawkę dość nagle. Główną wadą protokołu TCP jest to, że tylko 65 000 portów może być otwartych jednocześnie. Ale sposobem na rozwiązanie tego problemu byłoby przejście do farmy serwerów, która lepiej skaluje się wraz z obciążeniem, niż poprzez szybkie odzyskiwanie numerów portów. Po stronie klienta jest bardzo mało prawdopodobne, że zabraknie portów, jeśli jest to podstawowa stacja robocza.
źródło