W systemie Linux (moje serwery na żywo są w wersji RHEL 5.5 - poniższe łącza LXR dotyczą wersji jądra), man 7 ip
mówi:
Powiązany adres lokalnego gniazda TCP jest niedostępny przez pewien czas po zamknięciu, chyba że ustawiono flagę SO_REUSEADDR.
Nie używam SO_REUSEADDR
. Jak długo trwa „jakiś czas”? Jak mogę dowiedzieć się, jak długo to trwa i jak mogę to zmienić?
Rozglądam się po tym i znalazłem kilka drobiazgów informacji, z których żadne tak naprawdę nie wyjaśnia tego z perspektywy programisty aplikacji. To znaczy:
- TCP_TIMEWAIT_LEN w
net/tcp.h
to „jak długo czekać, aby zniszczyć stan CZAS OCZEKIWANIA”, i jest ustawiony na „około 60 sekund” - / proc / sys / net / ipv4 / tcp_fin_timeout to „Czas na utrzymanie gniazda w stanie FIN-WAIT-2, jeśli został zamknięty przez naszą stronę”, a „Domyślna wartość to 60 sekund”
Tam, gdzie potykam się, jest wypełnianie luki między modelem jądra cyklu życia TCP a modelem portów programisty niedostępnym, to znaczy w zrozumieniu, w jaki sposób te stany odnoszą się do „pewnego czasu”.
man 2 bind
jeśli mi nie wierzysz. Trzeba przyznać, że prawdopodobnie nie jest to pierwsza rzecz, o której ludzie uniksowi myślą, kiedy ktoś mówi „wiąż”, co jest dość sprawiedliwe.bind
, ale tutaj znacznik jest specjalnie stosowany na serwerze DNS. Nie mamy tagów dla każdego możliwego wywołania systemowego.Odpowiedzi:
Uważam, że idea, że gniazdo jest niedostępne dla programu, polega na umożliwieniu dotarcia segmentów danych TCP wciąż będących w tranzycie i odrzucenia ich przez jądro. Oznacza to, że aplikacja może wywoływać
close(2)
na gnieździe, ale opóźnienia routingu lub nieszczęścia w celu kontrolowania pakietów lub co możesz pozwolić drugiej stronie połączenia TCP na wysyłanie danych przez pewien czas. Aplikacja wskazała, że nie chce już zajmować się segmentami danych TCP, dlatego jądro powinno je po prostu odrzucić, gdy tylko się pojawią.Zhakowałem mały program w C, który możesz skompilować i użyć, aby sprawdzić, jak długi jest limit czasu:
Wypróbowałem ten program na 3 różnych komputerach i otrzymuję zmienny czas, od 55 do 59 sekund, kiedy jądro odmawia zezwolenia użytkownikowi innemu niż root na ponowne otwarcie gniazda. Skompilowałem powyższy kod do pliku wykonywalnego o nazwie „otwieracz” i uruchomiłem go w następujący sposób:
Otworzyłem kolejne okno i zrobiłem to:
To powoduje, że pierwsza instancja „otwieracza” akceptuje połączenie, a następnie je zamyka. Druga instancja „otwieracza”
bind(2)
co sekundę próbuje połączyć się z portem TCP 7896. „otwieracz” zgłasza od 55 do 59 sekund opóźnienia.Googlując się po okolicy, stwierdzam, że ludzie zalecają to:
aby skrócić ten interwał. Nie działało to dla mnie. Z 4 maszyn linuksowych, do których miałem dostęp, dwie miały 30, a dwie 60. Ustawiłem też tę wartość na 10. Nie ma różnicy w programie „otwieracza”.
Robiąc to:
zmienił rzeczy. Drugi „otwieracz” potrzebował tylko około 3 sekund, aby uzyskać nowe gniazdo.
źródło