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
.